无法跟踪实体类型的实例,因为已经跟踪了具有相同键的该类型的另一个实例 [英] The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked

查看:1012
本文介绍了无法跟踪实体类型的实例,因为已经跟踪了具有相同键的该类型的另一个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务对象Update

public bool Update(object original, object modified)
{
    var originalClient = (Client)original;
    var modifiedClient = (Client)modified;
    _context.Clients.Update(originalClient); //<-- throws the error
    _context.SaveChanges();
    //Variance checking and logging of changes between the modified and original
}

这是我从以下位置调用此方法的地方:

This is where I am calling this method from:

public IActionResult Update(DetailViewModel vm)
{
    var originalClient = (Client)_service.GetAsNoTracking(vm.ClientId);
    var modifiedClient = (Client)_service.Fetch(vm.ClientId.ToString());
    // Changing the modifiedClient here
    _service.Update(originalClient, modifiedClient);
}

这是GetAsNotTracking方法:

public Client GetAsNoTracking(long id)
{
    return GetClientQueryableObject(id).AsNoTracking().FirstOrDefault();
}

Fetch方法:

public object Fetch(string id)
{
   long fetchId;
   long.TryParse(id, out fetchId);
   return GetClientQueryableObject(fetchId).FirstOrDefault();
}

GetClientQueryableObject:

private Microsoft.Data.Entity.Query.IIncludableQueryable<Client, ActivityType> GetClientQueryableObject(long searchId)
{
    return _context.Clients
        .Where(x => x.Id == searchId)
        .Include(x => x.Opportunities)
        .ThenInclude(x => x.BusinessUnit)
        .Include(x => x.Opportunities)
        .ThenInclude(x => x.Probability)
        .Include(x => x.Industry)
        .Include(x => x.Activities)
        .ThenInclude(x => x.User)
        .Include(x => x.Activities)
        .ThenInclude(x => x.ActivityType);
 }

有什么想法吗?

我看了以下文章/讨论.无济于事: ASP.NET GitHub第3839版

I have looked the following articles / discussions. To no avail:ASP.NET GitHub Issue 3839

更新:

这是对GetAsNoTracking的更改:

public Client GetAsNoTracking(long id)
{
    return GetClientQueryableObjectAsNoTracking(id).FirstOrDefault();
}

GetClientQueryableObjectAsNoTracking:

private IQueryable<Client> GetClientQueryableObjectAsNoTracking(long searchId)
{
    return _context.Clients
        .Where(x => x.Id == searchId)
        .Include(x => x.Opportunities)
        .ThenInclude(x => x.BusinessUnit)
        .AsNoTracking()
        .Include(x => x.Opportunities)
        .ThenInclude(x => x.Probability)
        .AsNoTracking()
        .Include(x => x.Industry)
        .AsNoTracking()
        .Include(x => x.Activities)
        .ThenInclude(x => x.User)
        .AsNoTracking()
        .Include(x => x.Activities)
        .ThenInclude(x => x.ActivityType)
        .AsNoTracking();
}

推荐答案

在没有覆盖EF跟踪系统的情况下,您还可以在保存前分离本地"条目并附加更新的条目:

Without overriding EF track system, you can also Detach the 'local' entry and attach your updated entry before saving :

// 
var local = _context.Set<YourEntity>()
    .Local
    .FirstOrDefault(entry => entry.Id.Equals(entryId));

// check if local is not null 
if (local != null)
{
    // detach
    _context.Entry(local).State = EntityState.Detached;
}
// set Modified flag in your entry
_context.Entry(entryToUpdate).State = EntityState.Modified;

// save 
_context.SaveChanges();

更新: 为了避免代码冗余,可以执行扩展方法:

UPDATE: To avoid code redundancy, you can do an extension method :

public static void DetachLocal<T>(this DbContext context, T t, string entryId) 
    where T : class, IIdentifier 
{
    var local = context.Set<T>()
        .Local
        .FirstOrDefault(entry => entry.Id.Equals(entryId));
    if (!local.IsNull())
    {
        context.Entry(local).State = EntityState.Detached;
    }
    context.Entry(t).State = EntityState.Modified;
}

我的IIdentifier界面只有一个Id字符串属性.

My IIdentifier interface has just an Id string property.

无论您使用什么实体,都可以在上下文中使用此方法:

Whatever your Entity, you can use this method on your context :

_context.DetachLocal(tmodel, id);
_context.SaveChanges();

这篇关于无法跟踪实体类型的实例,因为已经跟踪了具有相同键的该类型的另一个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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