使用UnitOfWork模式和Entity Framework批量插入大量不同类型的记录的最佳方法。如果抛出错误或其他什么,我还需要反转。
我使用“SqlBulkCopy”工作正常但是当我将它包装到一个事务管理器中时,我得到一个关于它已经使用UnitOfWork打开的连接的错误。
我不能使用EntityFramework.Extensions,因为它不是开源的。
编辑 - 添加工作单元:
基本上,我遵循这个例子:click here
这是我的工作单位的具体课程:
public class UnitOfWork<TContext> : Disposable, IUnitOfWork<TContext> where TContext : DbContext, new()
{
private DbContext _context;
private bool _disposed;
private IGenericRepository<Log> _logRepository;
// other generic repositories
public UnitOfWork()
{
_context = new TContext();
}
public IGenericRepository<Log> LogRepository
=> _logRepository ?? (_logRepository = new GenericRepository<Log>(_context));
//getters for other repositories
//------------Public Function --------------------------------
public void Save()
{
_context.SaveChanges();
}
// this is the bulkInsert using SqlBulkCopy
//but getting error on the transactionscope due to opening a new connection
public virtual void BulkInsert<T>(DbContextTransaction tx, string tableName, System.Data.DataTable dataTable)
{
if (!Regex.IsMatch(dataTable.TableName, @"^[A-Za-z0-9\._]+$"))
{
return;
}
SqlTransaction sqlTx = (SqlTransaction)tx?.UnderlyingTransaction;
var columnNames =
_context.Database.SqlQuery<SysColumns>("SELECT c.Name, t.name as Type FROM sys.columns c JOIN sys.types t ON c.user_type_id = t.user_type_id WHERE object_id = OBJECT_ID('" + dataTable.TableName + "')");
if (columnNames == null)
{
return;
}
var connectionString = _context.Database.Connection.ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, sqlTx))
{
bulkCopy.DestinationTableName = tableName;
bulkCopy.BulkCopyTimeout = (int) TimeSpan.FromMinutes(10).TotalSeconds;
foreach (var column in dataTable.Columns)
{
var dbColumn =
columnNames.FirstOrDefault(x => string.Equals(x.Name, column.ToString(), StringComparison.CurrentCultureIgnoreCase));
if (dbColumn != null)
{
bulkCopy.ColumnMappings.Add(column.ToString(), dbColumn.Name);
}
}
bulkCopy.WriteToServer(dataTable);
}
connection.Close();
}
}
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
修改 - 添加更多代码:
public void ProcessData()
{
using (var transaction = new TransactionScope())
{
try
{
_repository.LogRepository.Insert(//log to initial import data)
ImportData();
_repository.LogRepository.Insert(//log to Complete import data)
_repository.Save();
}
catch (Exception e)
{
transaction.Dispose();
}
}
}
private void ImportData()
{
//Creating object of datatable
var tblcsv =
new DataTable("dbo.Table") { CaseSensitive = false };
//getting full file path of Uploaded file
var csvFilePath = _dataImportModel.RootPath + "\\Collector\\" + "data.csv";
//Reading All text
var readCsv = File.ReadAllText(csvFilePath);
foreach (var csvRow in readCsv.Split('\n'))
{
foreach (var fileColumn in csvRow.Split(','))
{
tblcsv.Columns.Add(fileColumn);
}
break;
}
//spliting row after new line
var rows = readCsv.Split('\n');
foreach (var csvRow in rows)
{
if (!string.IsNullOrEmpty(csvRow))
{
var count = 0;
var columnsData = SplitCsv(csvRow);
//Adding each row into datatable
tblcsv.Rows.Add();
foreach (var fileRec in columnsData)
{
tblcsv.Rows[tblcsv.Rows.Count - 1][count] =
string.IsNullOrEmpty(fileRec) ? null : fileRec;
count++;
}
}
}
_repository.BulkInsert<DataTable>(null, "dbo.Table", tblcsv);
}
答案 0 :(得分:0)
我查看了内部异常,错误消息是“合作伙伴事务管理器已禁用其对远程/网络事务的支持。(HRESULT异常:0x8004D025)
导致此问题发生的原因很多。
例如,在不关闭第一个连接的情况下打开连接而不是另一个连接可能导致这种错误:
using (var context = new CurrentContext())
{
using (var scope = new TransactionScope())
{
context.Database.Connection.Open();
using (var connection = new SqlConnection(context.Database.Connection.ConnectionString))
{
connection.Open();
using (var command = new SqlCommand("SELECT 1", connection))
{
var x = command.ExecuteNonQuery();
}
}
}
}