SQL Server. FILESTREAM. Методы доступа. Часть 5.

Мы продолжаем публикацию блогов по FILESTREAM.

В этом блоге мы рассмотрим методы доступа к данным FILESTREAM. Возможно в данной статье для вас не будет ничего нового, но мы решили опубликовать его, чтобы наш разговор о FILESTREAM был логично завершен.

Для доступа к FILESTREAM есть две возможности:

  1. Доступ с использованием языка Transact-SQL.
  2. Доступ из Win API специально предназначенного для такого доступа.

Доступ через Transact-SQL

Здесь все достаточно понятно и прозрачно. Для доступа используются стандартные DML-операторы, SELECT, INSERT, DELETE, UPDATE.

Особенностью операции UPDATE является то, что она не поддерживает частичное обновление файла и как результат выполняется как операция DELETE/INSERT.

Ниже приведены примеры выполнения таких операторов.

INSERT INTO dbo.FS_Records (Document)
VALUES (CAST(‘Yes, it””s work fine’ as varbinary(max)));
GO

SELECT *, cast (fsr.Document as char(100) ) as [Document text]
FROM dbo.FS_Records fsr;
GO

UPDATE FS_Records
SET Document = CAST(‘It is updated column’ as varbinary(max))
WHERE DocId = 2;
 GO

Единственно необычной вещью здесь является функция PathName(). В общем-то, для работы через Transact-SQL она не нужна, но через нее можно получить путь к файлу, который потом может быт передан в метод Win API для доступа к файлу лежащему на файловой системе.

Как было показано в предыдущих статьях эта функция не возвращает реального пути, но она дает точку перенаправления через драйвер RsFx0300xx к SQL Server-у.

Доступ через специальный Win API

Далее приводится пример доступа к FILESTREAM-файлам через Win API.

Пример написан на языке C# и имеет комментарии для каждой строки.

using System.IO;
using System;
using System.Data.SqlClient;
using System.Data.SqlTypes;

namespace FILESTREAM

{

  class Program

    {

   static void Main(string[] args)

       {

    string DocId = args[0]; //Параметр передаваемый из командной строки.

    SqlConnection sqlConnection = new SqlConnection(“Integrated Security=true;server=localhost\\SQL2014”); //Устанавливаем соединение к серверу

    SqlCommand sqlCommand = new SqlCommand();

    sqlCommand.Connection = sqlConnection;

    try

          {

            sqlConnection.Open();

     // Первое, что необходимо сделать, это получить путь к файлу SQL FILESTREAM BLOBа, через который приложение будет получать доступ к данным хранящимся в этом SQL FILESTREAM BLOB.
     // Для получения пути к файлу используется функция PathName().

     sqlCommand.CommandText = “SELECT Document.PathName() FROM FileStreamTest.dbo.FS_Records where DocId =” + DocId; //DocId – это аргумент, переданный из командной строки. 

     String filePath = null;

     Object pathObj = sqlCommand.ExecuteScalar();

     // Путь будет представлять строку типа
     // “\\\\ALEXAK-WS1\\SQL2014_FileStream\\v02-A60EC2F8-2B24-11DF-9CC3-AF2E56D89593\\FileStreamTest\\dbo\\FS_Records\\Document\\1895BA5E-F64E-45C5-9E22-65D225A69BD9\\VolumeHint-HarddiskVolume6”
     // С помощью даной строки будет осуществлено перенаправление запроса через общий ресурс \\ALEXAK-WS1\SQL2014_FileStream на реальный файл, как это описано в наших предыдущих блогах.

     if(pathObj==null)

       {

       throw new System.Exception(“There is no such Documents”);

       }

        if (DBNull.Value != pathObj) 

           {              

            filePath = (string)pathObj;

            }

        else

           {

            throw new System.Exception(“Document.PathName() failed to read the path name for the Document column.”);

            }

     // Далее необходимо получить контекст транзакции.
     // Все FILESTREAM BLOB операции ДОЛЖНЫ происходят внутри транзакций для того, чтобы избежать конфликтов с другими транзакциями,
     // например c транзакциями MARS, происходящими внутри специфических batch scoped транзакций.

     SqlTransaction fsTran = sqlConnection.BeginTransaction(“FileStreamTran”);

     sqlCommand.Transaction = fsTran;

     //Получаем контекст транзакции

     sqlCommand.CommandText =“SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()”;

     Object