簡體   English   中英

將文件表與實體框架以及級聯功能一起使用

[英]Using File Tables with Entity Framework as well as cascading functionality

SQL Server FileTable於 2012 年首次推出,但不受 Entity Framework(.NET Core 或完整的 .NET Framework)支持。 使用 SQL Server FileTableFileStream可以加快文件上傳和下載速度。

我想將FileTable與我的 .NET Core 應用程序一起使用,我必須在其中創建此FileTable與另一個簡單表的關系。

為此,我需要在 C# 中具有類型hierarchyid以及在 SQL Server 實例級別啟用文件流支持。 在更新遷移期間創建數據庫時,實體框架似乎不支持使用FileTable支持創建數據庫。

早些時候,當我想使用代碼優先方法將 SQL 文件表與我的 .Net Core 應用程序一起使用時,我問了這個問題並沒有找到答案。 好吧,既然我已經解決了這個問題,我想分享一下。 我不會詳細介紹每一個細節,但是,這是在 Microsoft 的網站上詳細定義的。

首先,您需要在 SQL Server 實例級別啟用文件流支持。 右鍵單擊 SQL Server 配置管理器中的 MSSQLSERVER 服務(我的 SQL Server 實例名稱是 MSSQLSERVER),然后選擇屬性。 在 FileStream 選項卡中,啟用前兩個復選框(“Enable Filestream for transact-SQL access & Enable Filestream for file I/O access”)。 然后重啟服務。

在 SQL Server Management Studio (SSMS) 中,右鍵單擊頂部節點(主要以您的計算機名稱命名)並單擊屬性。 轉到“高級”選項卡並根據您的需要更改 FILESTREAM 訪問級別(無論是事務 SQL 還是完全訪問)。

此后,您應該通過以下查詢創建數據庫:

CREATE DATABASE xyz
ON PRIMARY 
(NAME = FS,
    FILENAME = 'D:\Database\xyzDB.mdf'),
FILEGROUP FileStreamFS CONTAINS FILESTREAM(NAME = FStream, 
    FILENAME = 'D:\Database\xyzFs')
LOG ON 
(NAME = FILESDBLog,   
    FILENAME = 'D:\Database\xyzDBLog.ldf')
WITH FILESTREAM (NON_TRANSACTED_ACCESS = FULL, DIRECTORY_NAME = N'xyz')
GO

在這里, D:\Database是我存儲數據庫文件的目錄,包括將存儲在 SQL 文件表中的文件。 xyz是數據庫的名稱,后綴DB.mdfFsDBLog.ldf並在其后加上前綴N 我啟用NON_TRANSACTED_ACCESS 但如果您不想進行此類訪問,則可以禁用。 請注意,在運行此查詢之前,目錄必須存在。

現在您已經創建了數據庫,您可以繼續從您的 .Net 應用程序運行遷移,並在連接字符串中使用相同的數據庫名稱。

您還需要一個 SQL 函數來支持您的操作,我使用MigrationBuilder類創建了它:

migrationBuilder.Sql("CREATE FUNCTION dbo.HierarchyIdToString (@Id hierarchyid) RETURNS varchar(max) with schemabinding AS BEGIN RETURN CONVERT(varchar(max),CONVERT(varbinary(max),@Id,1),1); END");

migrationBuilder.SQL("CREATE FUNCTION StringToHierarchyId (@Id varchar(max)) "+
"RETURNS hierarchyid WITH SCHEMABINDING AS "+
"BEGIN "+
"RETURN CONVERT(hierarchyid,CONVERT(VARBINARY(MAX),@Id,1),1) "+
"END");

稍后,我將使用這個功能,並沿途解釋它的作用。

現在,創建將存儲您的文件的文件表。 您當然可以為不同類型的文件創建任意數量的文件表。

migrationBuilder.Sql("CREATE TABLE DocumentStore AS FILETABLE WITH (FileTable_Directory = 'DocumentStore', FileTable_Collate_Filename = database_default);");

我的文件表名稱是DocumentStore

您還需要一個存儲過程來獲取文件表根路徑(它存儲文件的位置),以便在文件系統級別訪問這些文件,以防您想以非事務方式訪問文件。 下面是代碼:

migrationBuilder.Sql("CREATE PROCEDURE GetFileTableRootPath @TableName VARCHAR(100), @Path VARCHAR(1000) OUTPUT AS BEGIN SET @Path = (SELECT FILETABLEROOTPATH(@TableName)) END");

請注意, FILETABLEROOTPATH('TableName')是我在存儲過程中使用的內置函數。 我知道如何在.Net 中調用存儲過程,所以我只是將函數包裝在存儲過程中。

我創建了另一個存儲過程來獲取存儲在文件表中的任何文件的Path_Locator Path_Locator 是文件表的主鍵,我稍后需要將其作為對該文件的引用輸入到另一個表中。 代碼是:

migrationBuilder.Sql("CREATE PROCEDURE GetFileTableRootPath @TableName VARCHAR(100), @Path VARCHAR(1000) OUTPUT AS BEGIN SET @Path = (SELECT FILETABLEROOTPATH(@TableName)) END");

我還使用名為Documents.cs的簡單 .Net 模型類創建了一個表,其中包括正常屬性(盡管重復,因為它們在文件表中也可用),包括在文件表中引用文件的屬性。 由於 File Table 的 PK 名稱為 Path_Locator 類型為HIERARCHYID ,因此我在Documents表中創建了varchar(max)字段,並將在從 SQL HIERARCHYID數據類型轉換為 SQL VARCHAR后將Path_Locator存儲在此列中。 該表是我的域類的一部分,並且將具有與表通常具有的關系。

現在我已經創建了支持表,我還需要實現 CASCADE DELETE 功能,這可以通過使用 SQL 觸發器來完成。 文件表上的第一個觸發器為:

migrationBuilder.Sql(
                "CREATE TRIGGER dbo.CascadeDelete ON DocumentStore "+
                "AFTER DELETE NOT FOR REPLICATION " +
                "AS "+
                "BEGIN "+
                "SET NOCOUNT ON "+
                "DECLARE @Id varchar(max); "+
                "DECLARE @Table Table (MyHierarchy hierarchyid); "+
                "INSERT INTO @Table SELECT deleted.path_locator from deleted; "+
                "WHILE ((SELECT COUNT(*) FROM @Table) > 0) "+
                "BEGIN "+
                "select @Id = dbo.HierarchyIdToString((SELECT TOP 1 * from @Table)); "+
                "DELETE FROM Documents WHERE HierarchyInString = @Id; "+
                "DELETE FROM @Table where MyHierarchy = dbo.StringToHierarchyId(@Id); "+
                "END END"
            );

第二個觸發器將使用名為Documents的遷移來處理表,以反映文件表中的文件刪除(同步數據庫):

migrationBuilder.Sql(
                "CREATE TRIGGER dbo.CascadeDeleteDocuments ON Documents AFTER DELETE NOT FOR REPLICATION AS BEGIN SET NOCOUNT ON DECLARE @Id hierarchyid; DECLARE @Table Table (MyHierarchyInString varchar(max)); INSERT INTO @Table SELECT deleted.HierarchyInString from deleted; WHILE ((SELECT COUNT(*) FROM @Table) > 0) BEGIN select @Id = dbo.StringToHierarchyId((SELECT TOP 1 * from @Table)); DELETE FROM DocumentStore WHERE path_locator = @Id; DELETE FROM @Table where MyHierarchyInString = dbo.HierarchyIdToString(@Id); END END");

要使用這些觸發器,我需要將HIERARCHYIDVARCHAR(MAX)進行轉換,反之亦然,為此我使用 SQL 標量函數來回轉換。

現在,要插入文件,我將存儲在從GETPATHLOCATOR存儲過程中檢索到的位置的 Windows 文件系統中,並且文件會自動存儲到我的文件表中。 同時,我還將一條記錄添加到從 C# 模型類創建的另一個表中,即維護兩個表的Documents

將來,我將嘗試使用文件流支持創建數據庫,使用應用程序中的一些代碼在 SQL Server 實例級別啟用文件流支持,以避免在代碼過程中出現這種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM