2012-05-07 13 views
9

Poprzednio I requested how to create a directory within a FileTable without using File I/O APIs. Teraz chcę utworzyć podkatalog do właśnie utworzonego katalogu nadrzędnego. Jak przypisać mój rodzic podczas wstawiania? Wygląda na to, że parent_path_locator jest kolumną wyliczoną.Tworzenie podkatalogu za pomocą SQL INSERT przy użyciu FileTable

Stwarza to mój rodzic ...

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

Jak mogę utworzyć katalog dziecko do tego rodzica w moim FileTable?

Odpowiedz

9

Właśnie tego użyłem do stworzenia podkatalogu, ponieważ GetPathLocator() nie wygeneruje dla mnie nowej wartości path_locator - będzie interpretować tylko istniejącą hierarchyids.

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); 

Powyższy blok kodowy wykorzystuje default path_locator value discovered here że buduje nowy hierarchyid reprezentacja GUID (wykorzystaniem newid() sposobu i prostą analizę). Funkcja GetNewPathLocator() nie istnieje nigdzie w SQL Server, którą mogłem znaleźć (hierarchyid.GetDescendant() jest najbliższy, jaki mogłem znaleźć, ale nie korzystał z natywnej struktury, której FileTable opiera się na). Może w 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 

Funkcja GetNewPathLocator() wymaga również widok SQL getNewID wniosek o newid() pomocą trick from this SO post.

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

Aby połączyć GetNewPathLocator(), można użyć parametru domyślnego który wygeneruje nowy hierarchyid lub przekazać w istniejącej reprezentacji hiearchyid smyczkową (.ToString()), aby stworzyć dziecku hierarchyid jak widać poniżej ...

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

Zamiast próbować odtworzyć hierarchyid w kodzie I zdecydowaliśmy się zaktualizować path_locator stworzony po to SQL własnego ID:

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) 

Gdzie "Assets" to nazwa mojego katalogu FileTable, "Test" to nazwa katalogu Chcę umieścić mój plik, "MyDoc.txt" to nazwa pliku, a 0x to zero dla strumienia pliku.

Jestem pewien, że mam zamiar przekształcić to w funkcję, dość łatwe.

See ...

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

Po pewnym rygorystycznych testów, wydaje oświadczenie aktualizacja jest skłonny do zakleszczenia, gdy nazywa się to równolegle. – Tod

0

Inną opcją jest użycie integracji CLR i tworzyć funkcje i procedury przechowywane w postaci kodu C#.

Właśnie stworzyłem projekt integracji GitHub CLR. https://github.com/rhyous/Db.FileTableFramework

Ma różne funkcje lub procedury, które chcesz: CreateFile, createDirectory, DirectoryExists. I na GitHub to oczywiście może być modyfikowane i ulepszane przez każdego.

0

zrobiłem pewną poprawę na odpowiedź:

  1. Funkcja zwraca hierarchyid zamiast napisu
  2. Jeśli jest rodzicem, hierarchyid :: funkcja GetReparentedValue służy do generowania nowego identyfikatora zamiast sznurka powiązanie.

    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 
    
Powiązane problemy