2012-05-07 9 views
9

Trước đây, I requested how to create a directory within a FileTable without using File I/O APIs. Bây giờ tôi muốn tạo một thư mục con vào thư mục cha mà tôi vừa tạo. Làm thế nào để gán bố mẹ tôi trong quá trình chèn? Có vẻ như parent_path_locator là cột được tính toán.Tạo thư mục con thông qua SQL INSERT bằng cách sử dụng FileTable

Điều này tạo ra cha mẹ của tôi ...

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

Làm thế nào để tạo một thư mục con để phụ huynh này trong FileTable của tôi?

Trả lời

9

Đây là những gì tôi đã kết thúc bằng cách tạo thư mục con kể từ GetPathLocator() sẽ không tạo giá trị path_locator mới cho tôi - nó sẽ chỉ giải thích hiện tại 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); 

Khối mã trên sử dụng các default path_locator value discovered here rằng xây dựng một hierarchyid đại diện mới từ một GUID (sử dụng newid() phương pháp, và đơn giản phân tích). Hàm GetNewPathLocator() không tồn tại ở bất kỳ đâu trong SQL Server mà tôi có thể tìm thấy (hierarchyid.GetDescendant() là gần nhất tôi có thể tìm thấy, nhưng nó không sử dụng cấu trúc gốc mà FileTable dựa trên). Có lẽ trong 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 

Chức năng GetNewPathLocator() cũng đòi hỏi một cái nhìn SQL getNewID yêu cầu một newid() sử dụng trick from this SO post.

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

Để gọi GetNewPathLocator(), bạn có thể sử dụng tham số mặc định mà sẽ tạo ra một mới hierarchyid hoặc vượt qua trong một đại diện hiearchyid chuỗi hiện có (.ToString()) để tạo ra một đứa trẻ hierarchyid như bên dưới ...

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

Thay vì cố gắng tạo lại hệ thống phân cấp trong mã tôi đã chọn để cập nhật path_locator sau khi SQL tạo id riêng của nó:

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) 

Trường hợp 'Nội dung' là tên của thư mục FileTable của tôi, 'Kiểm tra' là tên của Thư mục tôi muốn đặt tệp của mình vào, 'MyDoc.txt' là tên tệp và 0x là mục nhập 0 cho luồng phim.

Tôi chắc chắn rằng tôi sắp biến tính năng này thành một chức năng, đủ dễ dàng.

Xem ...

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

Sau một số thử nghiệm nghiêm ngặt, có vẻ như các báo cáo cập nhật là dễ bị bế tắc khi điều này được gọi là song song. – Tod

0

Một lựa chọn khác là sử dụng tích hợp CLR và tạo hàm và thủ tục được lưu trữ như C# mã.

Tôi vừa tạo dự án tích hợp GitHub CLR cho việc này. https://github.com/rhyous/Db.FileTableFramework

Có nhiều chức năng hoặc thủ tục khác nhau mà bạn muốn: CreateFile, CreateDirectory, DirectoryExists. Và trên GitHub nó tất nhiên có thể được sửa đổi và cải thiện bởi bất cứ ai.

0

tôi đã thực hiện một số cải tiến để câu trả lời:

  1. Các trở về chức năng HierarchyId thay vì chuỗi
  2. Nếu có một phụ huynh, HierarchyId :: GetReparentedValue chức năng được sử dụng để tạo ra một ID mới thay vì chuỗi nối.

    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