使用Entity Framework 4.3.1数据库首先,经常提交/保存对象更改到数据库的好方法是什么?在下面,我想在quickbooks电话之后立即保存发票,而不是等待发布所有发票的风险。但是,我不能每次在循环中调用SaveChanges,它会抛出异常。
在每个对象上使用.Save()方法会很方便,也许有一个很好的方法可以做到这一点?
var unpostedInvoices = entities.GetUnpostedInvoices();
foreach (Invoice invoice in unpostedInvoices)
{
// this takes a long time
var invoiceDto = quickbooks.PostInvoice(invoice);
invoice.Posted = true;
invoice.TransactionId = invoiceDto.TransactionId;
// I'd like to save here rather than after the foreach loop, but this will fail
//entities.SaveChanges();
}
// this works, but I don't want to risk waiting this long to save
entities.SaveChanges();
这是在循环中调用SaveChanges()时抛出的异常。
New transaction is not allowed because there are other threads running in the session.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest(Byte[] buffer, TransactionManagerRequestType request, String transactionName, TransactionManagerIsolationLevel isoLevel, Int32 timeout, SqlInternalTransaction transaction, TdsParserStateObject stateObj, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon(TransactionRequest transactionRequest, String transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, String name, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlInternalConnection.BeginTransaction(IsolationLevel iso)
at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.BeginTransaction(IsolationLevel isolationLevel)
at System.Data.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
答案 0 :(得分:7)
这个问题可能有所帮助:https://stackoverflow.com/questions/2113498
在您仍在阅读结果集时无法启动新交易,SaveChanges
创建交易(如果尚未存在)。
一种解决方案是首先完成读取,然后遍历内存中的结果集。
如果您更改此行:
var unpostedInvoices = entities.GetUnpostedInvoices().ToList();
...你能把SaveChanges
放回到循环中吗?
答案 1 :(得分:2)
EF将跟踪所有更改,并在您致电SaveChanges()
时更新数据库。
我不会在循环内调用SaveChanges()
(即使它不应该失败)。
请记住,EF会为您要插入,更新或删除的每条记录单独进行数据库往返,因此通常无关紧要的方式调用SaveChanges。只有在使用直接SQL并创建单个SqlCommand一次执行所有插入时,才能避免这种情况。
无论如何,此错误是由于实体框架在SaveChanges()
调用
using (var transaction = new TransactionScope())
{
using (var context = new MyContext())
{
foreach (Invoice invoice in unpostedInvoices)
{
// Change to invoice
context.SaveChanges();
}
}
transaction.Complete();
}