Ранее я задавал вопрос и не нашел ответа, когда хотел использовать SQL Таблицы файлов с моим. Net Базовым приложением, использующим код вначале. Хорошо, теперь, когда я решил проблему, я хотел бы поделиться этим. Я не буду вдаваться в подробности, однако это подробно описано на веб-сайте Microsoft.
Прежде всего, вам необходимо включить поддержку File Stream на SQL уровне экземпляра сервера. Щелкните правой кнопкой мыши службу MSSQLSERVER в SQL Диспетчер конфигурации сервера (мой SQL Имя экземпляра сервера было MSSQLSERVER) и выберите свойства. На вкладке FileStream включите первые два флажка («Включить файловый поток для доступа transact- SQL и Включить файловый поток для доступа к файлу ввода-вывода»). Затем перезапустите службу.
В SQL Server Management Studio (SSMS) щелкните правой кнопкой мыши верхний узел (в основном по имени вашего компьютера) и выберите Свойства. Go на вкладку «Дополнительно» и измените уровень доступа 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 File Table. xyz
- имя суффикса базы данных DB.mdf
, Fs
& DBLog.ldf
и префикс N
после этого. Я включил NON_TRANSACTED_ACCESS
; но вы можете отключить, если вы не хотите такой доступ. Обратите внимание, что каталог должен существовать до запуска этого запроса.
Теперь, когда вы создали базу данных, вы можете go вперед и запустить миграцию из вашего. 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
.
Вам также потребуется хранимая процедура для получите путь к таблице файлов Root (где хранятся файлы), чтобы получить доступ к этим файлам на уровне файловой системы, на случай, если вы хотите получить доступ к файлам нетранзакционными способами. Ниже приведен код:
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");
Я также создал таблицу с использованием простого. Net Класс модели с именем Documents.cs
, включая обычные атрибуты (повторяются, хотя они также доступны в таблице файлов), включая атрибут для справочный файл в таблице файлов. Поскольку File Table имеет PK с именем Path_Locator с типом HIERARCHYID
, я создал поле varchar(max)
в таблице Documents
и сохраню Path_Locator
в этом столбце после преобразования в SQL VARCHAR
из SQL HIERARCHYID
тип данных. Эта таблица является частью классов моего домена и будет иметь отношения, как обычно у таблицы.
Теперь, когда я создал вспомогательные таблицы, мне также нужно реализовать функциональность 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");
Чтобы эти триггеры работали, мне нужно было преобразовать HIERARCHYID
с VARCHAR(MAX)
и наоборот, для чего я использовал SQL Скалярные функции для преобразования туда и обратно.
Теперь, чтобы вставить файлы, я сохраняю в windows файловую систему в месте, извлеченном из хранимой процедуры GETPATHLOCATOR
, и файл автоматически сохраняется в моей таблице файлов. Одновременно я также добавляю запись в свою другую таблицу, созданную из C# класса модели, т.е. Documents
, поддерживающего обе таблицы.
В будущем я попытаюсь создать базу данных с поддержкой File Stream, включить поддержку File Stream на SQL Уровень экземпляра сервера с использованием некоторого кода из приложения, чтобы избежать этого из процесса кода.
Спасибо.