Wyodrębniam zawartość plików w tabeli plików SQL. Poniższy kod działa, jeśli nie używam Parallel.Threading i SqlFileStream. Proces nie może uzyskać dostępu do określonego pliku, ponieważ został otwarty w innej transakcji
Otrzymuję następujący wyjątek podczas odczytu strumienia pliku sql jednocześnie (Parallel).
Proces nie może uzyskać dostępu do określonego pliku, ponieważ został otwarty w innej transakcji.
TL, DR:
Podczas odczytu pliku z FileTable (stosując GET_FILESTREAM_TRANSACTION_CONTEXT) w Parallel.ForEach uzyskać powyższego wyjątku.
Przykładowy kod, aby wypróbować:
https://gist.github.com/NerdPad/6d9b399f2f5f5e5c6519
dłuższa wersja:
Fetch Osprzęt i wyodrębnić zawartość:
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 Czytaj File Table:
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;
}
}
Tworzenie obiektów dla każdego pliku: Obiekt zawiera odniesienie do 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()
...
...
};
}
}
Czytaj plik używając SqlFileStream: Wyjątkiem jest wyrzucony tutaj
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
}
....
}
Aktualizacja 1:
Według this artykułu wydaje się, że może to być problem poziom izolacji. Czy ktoś kiedykolwiek stanął przed podobnym problemem?
Spróbuj otworzyć plik w tym samym wątku, który wykonał resztę kodu SQL. Może to po prostu nie jest dozwolone. – usr
Piszesz do 'dokumentów' na wielu wątkach,' Lista 'nie jest bezpieczna dla wątków i nie możesz tego zrobić (To nie jest prawdopodobne źródło twojego problemu, ale jest to problem) –