14

SQL ファイル テーブル内のファイルのコンテンツを抽出しています。次のコードは、Parallel を使用しない場合に機能します。

SQLファイルストリームを同時に(パラレル)読み取ると、次の例外が発生します。

指定されたファイルは別のトランザクションで開かれているため、プロセスはアクセスできません。

TL;DR:

Parallel.ForEach で (GET_FILESTREAM_TRANSACTION_CONTEXT を使用して) FileTable からファイルを読み取ると、上記の例外が発生します。

試してみるサンプルコード:

https://gist.github.com/NerdPad/6d9b399f2f5f5e5c6519

より長いバージョン:

添付ファイルを取得し、コンテンツを抽出します。

var documents = new List<ExtractedContent>();
using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
    var attachments = await dao.GetAttachmentsAsync();

    // Extract the content simultaneously
    // documents = attachments.ToDbDocuments().ToList(); // This works
    Parallel.ForEach(attachments, a => documents.Add(a.ToDbDocument())); // this doesn't

    ts.Complete();
}

DAO 読み取りファイル テーブル:

public async Task<IEnumerable<SearchAttachment>> GetAttachmentsAsync()
{
    try
    {
        var commandStr = "....";

        IEnumerable<SearchAttachment> attachments = null;
        using (var connection = new SqlConnection(this.DatabaseContext.Database.Connection.ConnectionString))
        using (var command = new SqlCommand(commandStr, connection))
        {
            connection.Open();

            using (var reader = await command.ExecuteReaderAsync())
            {
                attachments = reader.ToSearchAttachments().ToList();
            }
        }

        return attachments;
    }
    catch (System.Exception)
    {
        throw;
    }
}

ファイルごとにオブジェクトを作成します。オブジェクトには、GET_FILESTREAM_TRANSACTION_CONTEXT への参照が含まれています。

public static IEnumerable<SearchAttachment> ToSearchAttachments(this SqlDataReader reader)
{
    if (!reader.HasRows)
    {
        yield break;
    }

    // Convert each row to SearchAttachment
    while (reader.Read())
    {
        yield return new SearchAttachment
        {
            ...
            ...
            UNCPath = reader.To<string>(Constants.UNCPath),
            ContentStream = reader.To<byte[]>(Constants.Stream) // GET_FILESTREAM_TRANSACTION_CONTEXT() 
            ...
            ...
        };
    }
}

SqlFileStream を使用してファイルを読み取る: ここで例外がスローされます

public static ExtractedContent ToDbDocument(this SearchAttachment attachment)
{
    // Read the file
    // Exception is thrown here
    using (var stream = new SqlFileStream(attachment.UNCPath, attachment.ContentStream, FileAccess.Read, FileOptions.SequentialScan, 4096))
    {
        ...
        // extract content from the file
    }

    ....
}

更新 1:

この記事によると、分離レベルの問題である可能性があるようです。誰かが同様の問題に直面したことがありますか?

4

1 に答える 1