使用FileTable通过SQL INSERT创建子目录

时间:2012-05-07 16:57:30

标签: sql filestream sql-server-2012 filetable

以前,I requested how to create a directory within a FileTable without using File I/O APIs。我现在想要创建一个我刚刚创建的父目录的子目录。如何在插入期间指定我的父母?似乎parent_path_locator是计算列。

这会创建我的父母......

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

如何在FileTable中为此父目录创建子目录?

4 个答案:

答案 0 :(得分:10)

这是我最终用于创建子目录的内容,因为GetPathLocator()不会为我生成新的path_locator值 - 它只会解释现有的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);

上面的代码块使用default path_locator value discovered here从GUID构建新的hierarchyid表示(利用newid()方法,以及简单的解析)。函数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()还需要SQL视图getNewID才能使用trick from this SO post请求newid()

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

要致电GetNewPathLocator(),您可以使用默认参数生成新hierarchyid或传入现有hiearchyid字符串表示形式( .ToString() )创建一个孩子hierarchyid,如下所示......

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

答案 1 :(得分:0)

我没有尝试在代码中重新创建hierarchyid,而是在SQL创建了自己的id之后选择更新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)

资产'是我的FileTable目录的名称,'测试'是我想要将文件放入的目录的名称,' 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

答案 2 :(得分:0)

另一种选择是使用CLR集成并创建函数和存储过程作为C#代码。

我刚为此创建了一个GitHub CLR集成项目。 https://github.com/rhyous/Db.FileTableFramework

它具有您需要的各种功能或过程:CreateFile,CreateDirectory,DirectoryExists。在GitHub上,它当然可以被任何人修改和改进。

答案 3 :(得分:0)

我对答案做了一些改进:

  1. 该函数返回hierarchyid而不是string
  2. 如果有父级,则使用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