2012-05-07 24 views
9

以前はI requested how to create a directory within a FileTable without using File I/O APIsでした。今作成した親ディレクトリへのサブディレクトリを作成したい。挿入時に私の親をどのように割り当てるのですか? parent_path_locatorは計算された列であるようです。FileTableを使用したSQL INSERTによるサブディレクトリの作成

これは私の親が作成されます...

INSERT INTO FileTable0 (name,is_directory,is_archive) VALUES ('Directory', 1, 0); 

は、どのように私は自分のFileTable内でこの親に子ディレクトリを作成するのですか?それだけでhierarchyidsを既存解釈する -

答えて

9

これはGetPathLocator()が私のために新しいpath_locator値を生成しないので、私はサブディレクトリを作成するために使用してしまったものです。

DECLARE @parentdir table(path hierarchyid not null); 
DECLARE @subdir_locator hierarchyid 

-- Create Parent Directory, OUTPUT inserted parent path 
INSERT INTO FileTable0 (name,is_directory,is_archive) 
OUTPUT INSERTED.path_locator into @parentdir 
SELECT 'Directory', 1, 0 

-- Create new path_locator based upon parent 
SELECT @subdir_locator = dbo.GetNewPathLocator(path) from @parentdir 

-- Create Subdirectory 
INSERT INTO FileTable0 (name,path_locator,is_directory,is_archive) 
VALUES ('subdirectory', @subdir_locator, 1, 0); 

上記のコードブロックは、GUID(利用newid()方法、及び単純な解析)から新しいhierarchyid表現を構築default path_locator value discovered hereを利用します。関数GetNewPathLocator()は、私が見つけることができるSQL Serverのどこにも存在しません(hierarchyid.GetDescendant()が最も近いですが、FileTableがに依存するネイティブ構造を使用していません)。たぶんSQL.NEXTに...

CREATE FUNCTION dbo.GetNewPathLocator (@parent hierarchyid = null) RETURNS varchar(max) AS 
BEGIN  
    DECLARE @result varchar(max), @newid uniqueidentifier -- declare new path locator, newid placeholder  
    SELECT @newid = new_id FROM dbo.getNewID; -- retrieve new GUID  
    SELECT @result = ISNULL(@parent.ToString(), '/') + -- append parent if present, otherwise assume root 
        convert(varchar(20), convert(bigint, substring(convert(binary(16), @newid), 1, 6))) + '.' + 
        convert(varchar(20), convert(bigint, substring(convert(binary(16), @newid), 7, 6))) + '.' + 
        convert(varchar(20), convert(bigint, substring(convert(binary(16), @newid), 13, 4))) + '/'  
    RETURN @result -- return new path locator  
END 
GO 

機能GetNewPathLocator()trick from this SO postを使用してnewid()を要求するためのSQLビューgetNewIDが必要です。

create view dbo.getNewID as select newid() as new_id 

GetNewPathLocator()を呼び出すには、新しいhierarchyidを生成するか、下のような子hierarchyidを作成するために、既存のhiearchyid文字列表現(.ToString())に渡しますデフォルトのパラメータを...使用することができます

SELECT dbo.GetNewPathLocator(DEFAULT); -- returns /260114589149012.132219338860058.565765146/ 
SELECT dbo.GetNewPathLocator('/260114589149012.132219338860058.565765146/'); -- returns /260114589149012.132219338860058.565765146/141008901849245.92649220230059.752793580/ 
0

コードでhierarchyidを再作成するのではなく、SQLを作成した後にpath_locatorを更新することを選択しました。

DECLARE @pathID hierarchyid; 
DECLARE @parentdir table(path hierarchyid not null); 

IF NOT EXISTS(SELECT 1 FROM FileAsset WHERE is_directory = 1 AND file_stream.GetFileNamespacePath() = '\Assets\Test') 
INSERT INTO FileAsset (name, is_directory) VALUES('Test', 1) 

SELECT @pathID = FileAsset.path_locator FROM FileAsset WHERE file_stream.GetFileNamespacePath() = '\Assets\Test' 

INSERT INTO FileAsset (name, file_stream) OUTPUT INSERTED.path_locator into @parentdir VALUES('MyDoc.txt', 0x) 

UPDATE FileAsset SET path_locator = '/' + REPLACE(@pathID.ToString(), '/','') + path_locator.ToString() WHERE path_locator = (SELECT [path] FROM @parentdir) 

ここで、 'Assets'はFileTableディレクトリの名前、 'Test'はディレクトリ名、MyDoc.txtはファイル名、0xはファイルストリームのゼロエントリです。

私はこれを関数に簡単に変換しようとしています。

見る

CREATE PROCEDURE InsertFileAsset 

    @fileName varchar(255), 
    @dirName varchar(255), 
    @data varbinary(MAX), 
    @stream_id uniqueidentifier OUTPUT 
AS 
BEGIN 
    DECLARE @pathID hierarchyid; 
    DECLARE @parentdir table(path hierarchyid not null); 
    DECLARE @streamID table(streamID uniqueidentifier not null); 

    IF NOT EXISTS(SELECT 1 FROM FileAsset WHERE is_directory = 1 AND file_stream.GetFileNamespacePath() = '\Assets\' + @dirName) 
    INSERT INTO FileAsset (name, is_directory) VALUES(@dirName, 1) 

    SELECT @pathID = FileAsset.path_locator FROM FileAsset WHERE file_stream.GetFileNamespacePath() = '\Assets\' + @dirName 

    INSERT INTO FileAsset (name, file_stream) OUTPUT INSERTED.path_locator into @parentdir VALUES(@fileName, @data) 

    UPDATE FileAsset SET path_locator = '/' + REPLACE(@pathID.ToString(), '/','') + path_locator.ToString() OUTPUT inserted.stream_id INTO @streamID WHERE path_locator = (SELECT [path] FROM @parentdir) 

    SELECT @stream_id = streamID FROM @streamID 

    RETURN 
END 
GO 
+0

は、いくつかの厳密なテストの後、これが並列に呼び出されたときに更新ステートメントがデッドロックになりやすいようです。 – Tod

0

別のオプションは、CLR統合を使用し、C#のコードとして機能し、ストアドプロシージャを作成することです。

私は、このためにGitHub CLR統合プロジェクトを作成しました。 https://github.com/rhyous/Db.FileTableFramework

これには、CreateFile、CreateDirectory、DirectoryExistsなど、さまざまな機能や手順があります。もちろん、GitHub上であれば誰でも変更して改善することができます。

0

私は答えにいくつかの改善をした:

  1. 親がある場合は代わりに、文字列
  2. のhierarchyid型の関数が戻ると、hierarchyid型:: GetReparentedValue関数は文字列の代わりに新しいIDを生成するために使用されます連結。

    create function doc.GetNewPathLocator (@parent hierarchyid = null) returns hierarchyid 
    as 
    begin 
        declare @id uniqueidentifier = (select new_id from dbo.GetNewID); 
        declare @path hierarchyid = (convert(hierarchyid, '/' + 
          convert(varchar(20), convert(bigint, substring(convert(binary(16), @id), 1, 6))) + '.' +  
          convert(varchar(20), convert(bigint, substring(convert(binary(16), @id), 7, 6))) + '.' +  
          convert(varchar(20), convert(bigint, substring(convert(binary(16), @id), 13, 4))) + '/')); 
        return case when @parent is null then @path else @path.GetReparentedValue(hierarchyid::GetRoot(), @parent) end; 
    end 
    go