【问题标题】:Frequent saves with entity framework使用实体框架进行频繁保存
【发布时间】:2012-06-06 13:41:16
【问题描述】:

使用 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)

【问题讨论】:

  • 在循环内调用SaveChanges怎么会失败?
  • 我在问题中添加了例外。

标签: .net entity-framework


【解决方案1】:

这个问题可能会有所帮助:https://stackoverflow.com/questions/2113498

当您仍在读取结果集时,您无法启动新事务,如果尚不存在,SaveChanges 会创建一个事务。

一种解决方案是先完成读取,然后遍历内存中的结果集。

如果你改变这一行:

var unpostedInvoices = entities.GetUnpostedInvoices().ToList();

...你能把SaveChanges放回循环中吗?

【讨论】:

  • 是的,这就是工作。谢谢!
  • 我仍然不明白为什么在我们仍在读取结果集时无法启动新事务。技术原因是什么?
【解决方案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();
}

【讨论】:

  • 是的,我想每次通过循环而不是最后都发出更新(数据库往返)。但是,每次调用 SaveChanges() 都不起作用。由于我使用 sprocs 进行插入和更新,因此我将研究只对更新执行函数导入并直接在上下文中调用它。
  • 谢谢,有道理。在这种情况下,我希望每个更新都能独立运行,并且如果循环中稍后的发票失败,则不会回滚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多