以前,我请求过如何在FileTable
不使用文件 I/O API的情况下在 a 中创建目录。我现在想为我刚刚创建的父目录创建一个子目录。在插入期间如何分配我的父母?看来这parent_path_locator
是一个计算列。
这创造了我的父母......
INSERT INTO FileTable0 (name,is_directory,is_archive) VALUES ('Directory', 1, 0);
如何在我的 FileTable 中为该父级创建一个子目录?
以前,我请求过如何在FileTable
不使用文件 I/O API的情况下在 a 中创建目录。我现在想为我刚刚创建的父目录创建一个子目录。在插入期间如何分配我的父母?看来这parent_path_locator
是一个计算列。
这创造了我的父母......
INSERT INTO FileTable0 (name,is_directory,is_archive) VALUES ('Directory', 1, 0);
如何在我的 FileTable 中为该父级创建一个子目录?
这就是我最终用来创建子目录的内容,因为它不会为我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);
上面的代码块利用了此处发现的默认 path_locator 值hierarchyid
,该值从 GUID构建新表示(利用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
来请求newid()
使用此 SO post 中的技巧。
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/
我没有尝试在代码中重新创建 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)
其中“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
另一种选择是使用 CLR 集成并将函数和存储过程创建为 C# 代码。
我刚刚为此创建了一个 GitHub CLR 集成项目。 https://github.com/rhyous/Db.FileTableFramework
它具有您想要的各种功能或过程:CreateFile、CreateDirectory、DirectoryExists。当然,在 GitHub 上,任何人都可以对其进行修改和改进。
我对答案做了一些改进:
如果有父级,则使用 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