EF Core连续更新数据实体,报错已在跟踪另一个键值为“{Id:xxxxxx}”的实例。附着现有实体时,请确保仅附着一个具有给定键值的实体实例

        当使用EF Core对同一数据实体进行连续更新时,有时会发生跟踪实体异常,即便使用EF Core的数据仓储查询数据时已经设置了DetachedEntities(不跟踪的脱轨实体),依旧会发成此错误。

        我一度以为是使用了异步方法的原因,后来查询updateNow返回的消息后,发现实体状态Sate为unChanged,说明此数据还未被更新到数据库,EF Core依旧保持着对该实体的跟踪状态.

_mainBill.UpdateNow(mainBill).State

        查询State的值后,发现此参数是一个枚举值,它包含了(该枚举类来自EF Core对EntityState的反编译):

public enum EntityState
    {
        //
        // 摘要:
        //     The entity is not being tracked by the context.
        Detached,
        //
        // 摘要:
        //     The entity is being tracked by the context and exists in the database. Its property
        //     values have not changed from the values in the database.
        Unchanged,
        //
        // 摘要:
        //     The entity is being tracked by the context and exists in the database. It has
        //     been marked for deletion from the database.
        Deleted,
        //
        // 摘要:
        //     The entity is being tracked by the context and exists in the database. Some or
        //     all of its property values have been modified.
        Modified,
        //
        // 摘要:
        //     The entity is being tracked by the context but does not yet exist in the database.
        Added
    }

        查阅资料并进行几次尝试后,在执行UpdateNow操作后,通过获取当前数据实体的数据库上下文,并设置对该实体不再跟踪,连续的EF Core更新同一数据实体就不在抛出跟踪异常了

示例代码如下:

第一种方法:数据仓储更新数据,手动设置数据库上下文取消对当前实体的跟踪

_mainBill.UpdateNow(mainBill);
_mainBill.Context.Entry(mainBill).State = EntityState.Detached;//更新后取消跟踪

第二种方法:完全由数据库上下文执行更新操作

//获取当前数据库上线文(_mainBill是数据仓储IRepository<MainBill>),也可以直接使用你自己设定的
//databaseContext
var Context=_mainBill.Context;
Context.Attach<MainBill>(mainBill);//添加数据实体到数据库上下文中
Context.Entry<MainBill>(mainBill).State = EntityState.Modified;//修改操作
Context.SaveChanges();//提交保存更改
Context.Entry<MainBill>(mainBill).State = EntityState.Detached;//取消跟踪

        虽然这里设施数据库上下文不在跟踪实体,但不会影响当前的数据更新操作,只是指定EF Core不在对此实体进行跟踪。

以下是我查询ChatGpt给出的资料:

        这个错误通常发生在EF Core上下文中重复跟踪相同键值的实体时。为了解决这个问题,您可以尝试以下几种方法:

        1.使用AsNoTracking()方法:在第二次调用UpdateNow()之前,使用AsNoTracking()方法来禁用对实体的跟踪。这样可以确保第二次更新操作不会与之前跟踪的实体冲突。

// 更新操作
context.EcOrder.AsNoTracking().UpdateNow(updatedEcOrder);

// 第二次更新操作
context.EcOrder.AsNoTracking().UpdateNow(anotherUpdatedEcOrder);

        2.分离实体对象:在第一次更新操作完成后,使用Detach()方法将实体对象从上下文中分离,然后进行第二次更新操作。

// 更新操作
context.EcOrder.UpdateNow(updatedEcOrder);

// 分离实体对象
context.Entry(updatedEcOrder).State = EntityState.Detached;

// 第二次更新操作
context.EcOrder.UpdateNow(anotherUpdatedEcOrder);

        3.创建新的上下文实例:如果以上方法无效,您可以考虑创建一个新的上下文实例来执行第二次更新操作。这样可以确保每个更新操作都在独立的上下文中进行,避免实体跟踪冲突。

// 第一个上下文实例
using (var context = new YourDbContext())
{
    // 更新操作
    context.EcOrder.UpdateNow(updatedEcOrder);
}

// 第二个上下文实例
using (var anotherContext = new YourDbContext())
{
    // 第二次更新操作
    anotherContext.EcOrder.UpdateNow(anotherUpdatedEcOrder);
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值