实体框架 - “由于在会话中运行的其他线程”不允许新事务“ [英] Entity Framework - "New transaction is not allowed because there are other threads running in the session"

查看:70
本文介绍了实体框架 - “由于在会话中运行的其他线程”不允许新事务“的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


System.Data.SqlClient.SqlException:新事务是不允许,因为会话中还有其他线程。


我已经看到了这个问题的各种答案,但我似乎不能得到他们中的任何一个工作,基本上我正在保存我的存储库内的一个事务中的大量项目,我必须循环通过几个项目删除它们并写一个审计记录。



我已经看到的所有其他答案(例如 Mark Staffords答案)建议声明一个明确的事务(我有),或者在完成循环后只调用保存更改(这不是一个选项,因为审计目前工作的方式 - 需要审计ID写审核详细记录)。 p>

每当在delete方法中调用SaveChanges时,会抛出错误,请参见下文 -

 code> public virtual void Save(DoseReturn oldDoseReturn)
{
//保存开始时获取日期时间
DateTime saveStartTime = DateTime.Now;
字典< string,object> oldValues = new Dictionary< string,object>();
字典< string,object> newValues = new Dictionary< string,object>();

//获取对象上下文并打开一个新事务
ObjectContext objectContext =((IObjectContextAdapter)context).ObjectContext;
objectContext.Connection.Open();
DbTransaction transaction = objectContext.Connection.BeginTransaction();

//使用事务处理所有更新
使用(transaction)
{
if(oldDoseReturn!= null)
{
IDoseReturnStatusRepository statusRepository = new DoseReturnStatusRepository();
var list = statusRepository.AsQueryable()。其中​​(x => x.DoseReturnID == oldDoseReturn.DoseReturnID);

foreach(列表中的var项)
{
statusRepository.Delete(item,objectRetrievedDateTime,objectContext,saveStartTime,out oldValues,out newValues);
}

context.SaveChanges();

//获取相关的存储库
IDoseReturnsRepository repository = new DoseReturnsRepository();

//审计和删除对象
repository.Delete(oldDoseReturn,objectRetrievedDateTime,objectContext,saveStartTime,out oldValues,out newValues);

context.SaveChanges();
}
}

try
{
//进行最后的保存,然后提交事务
context.SaveChanges();
transaction.Commit();
}
catch(Exception ex)
{
//发生错误,回滚事务并关闭连接,然后出现错误
transaction.Rollback( );
objectContext.Connection.Close();
throw ex;
}
//关闭连接
objectContext.Connection.Close();


public virtual void Delete(T entity,DateTime?objectRetrievedDateTime,ObjectContext objectContext,DateTime saveStartTime,out Dictionary< string,object> oldValues,out Dictionary< string,object> newValues)
{
oldValues = new Dictionary< string,object>();
newValues = new Dictionary< string,object>();

if(entity == null)
{
throw new ArgumentException(无法更新空实体);
}

string entityName = entity.GetType()。Name;

if(!objectRetrievedDateTime.HasValue ||!this.AuditsAfterRetieval(objectRetrievedDateTime,entityName,entity,saveStartTime))
{
this.DeletedEntityAudit(entity,out oldValues,out newValues );

context.Entry(entity).State = System.Data.EntityState.Deleted;
this.context.Set&T;()。Remove(entity);
this.Audit(entity,entityName,Delete,oldValues,newValues,true);
this.context.SaveChanges();
}
else
{
throw new Exception(Object is not be as as it has been modified in another thread);
}
}


解决方案

可能是因为您在尝试保存更改时枚举结果。



尝试更改此行:

  var list = statusRepository.AsQueryable ()
.Where(x => x.DoseReturnID == oldDoseReturn.DoseReturnID);

to:

 code> var list = statusRepository.AsQueryable()
.Where(x => x.DoseReturnID == oldDoseReturn.DoseReturnID)
.ToList();

作为辅助调用 .SaveChanges()

I am getting the following error trying to save changes in entity framework -

System.Data.SqlClient.SqlException: New transaction is not allowed because there are other threads running in the session.

I have seen various answers to this problem, but I cannot seem to get any of them to work, basically I am saving a large number of items in a transaction inside my repository, I have to loop through several items to delete them and write an audit record.

All other answers I have seen for this (E.g. Mark Staffords Answer) suggest declaring an explicit transaction (which I have) or by only calling save changes after completing the loop (this is not an option due to the way auditing currently works - the audit ID is required to write the audit details records).

The error is thrown whenever 'SaveChanges' is called inside the delete method, see below -

public virtual void Save(DoseReturn oldDoseReturn)
{
    // Get the datetime when the save started
    DateTime saveStartTime = DateTime.Now;
    Dictionary<string, object> oldValues = new Dictionary<string, object>();
    Dictionary<string, object> newValues = new Dictionary<string, object>();

    // Get the object context and open a new transaction
    ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
    objectContext.Connection.Open();
    DbTransaction transaction = objectContext.Connection.BeginTransaction();

    // Use the transaction for all updates
    using (transaction)
    {
        if (oldDoseReturn != null)
        {
              IDoseReturnStatusRepository statusRepository = new DoseReturnStatusRepository();
              var list = statusRepository.AsQueryable().Where(x => x.DoseReturnID == oldDoseReturn.DoseReturnID);

              foreach (var item in list)
              {
                  statusRepository.Delete(item, objectRetrievedDateTime, objectContext, saveStartTime, out oldValues, out newValues);
              }

              context.SaveChanges();

              // Get the relevant repository
              IDoseReturnsRepository repository = new DoseReturnsRepository();

              // audit and delete the object
              repository.Delete(oldDoseReturn, objectRetrievedDateTime, objectContext, saveStartTime, out oldValues, out newValues);

              context.SaveChanges();
         }
    }

    try
    {
         // Conduct a final save, then commit the transaction
         context.SaveChanges();
         transaction.Commit();
    }
    catch (Exception ex)
    {
         // An error has occurred, rollback the transaction and close the connection, then present the error
         transaction.Rollback();
         objectContext.Connection.Close();
         throw ex;
    }
    // Close the connection
    objectContext.Connection.Close();
}

public virtual void Delete(T entity, DateTime? objectRetrievedDateTime, ObjectContext objectContext, DateTime saveStartTime, out Dictionary<string, object> oldValues, out Dictionary<string, object> newValues)
    {
        oldValues = new Dictionary<string, object>();
        newValues = new Dictionary<string, object>();

        if (entity == null)
        {
            throw new ArgumentException("Cannot update a null entity.");
        }

        string entityName = entity.GetType().Name;

        if (!objectRetrievedDateTime.HasValue || !this.AuditsAfterRetieval(objectRetrievedDateTime, entityName, entity, saveStartTime))
        {
            this.DeletedEntityAudit(entity, out oldValues, out newValues);

            context.Entry(entity).State = System.Data.EntityState.Deleted;
            this.context.Set<T>().Remove(entity);
            this.Audit(entity, entityName, "Delete", oldValues, newValues, true);
            this.context.SaveChanges();
        }
        else
        {
            throw new Exception("Object cannot be saved as it has been amended in another thread");
        }
    }

解决方案

This might be because you are enumerating results when trying to save changes.

Try changing this line:

var list = statusRepository.AsQueryable()
               .Where(x => x.DoseReturnID == oldDoseReturn.DoseReturnID);

to:

var list = statusRepository.AsQueryable()
               .Where(x => x.DoseReturnID == oldDoseReturn.DoseReturnID)
               .ToList();

As a side note invoking .SaveChanges() inside a loop is usually not a good idea as it is in general an expensive operation (talks to the database).

这篇关于实体框架 - “由于在会话中运行的其他线程”不允许新事务“的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆