首页 新闻 会员 周边 捐助

EF CORE 的tracked问题

0
悬赏园豆:5 [已解决问题] 解决于 2023-06-20 13:56

查询时已加入AsNoTracking设置不追踪,为什么UpdateRange更新时还是会报tracked的相关错误?

错误信息

异常信息:The instance of entity type 'Wxuserdatum' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values. 
异常明细:   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, Nullable`1 fallbackState)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.SetEntityStates(IEnumerable`1 entities, EntityState entityState)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.UpdateRange(IEnumerable`1 entities)
   at Tencent.DB.WxWorkSyncHelper.PullUser() in E:\KangShuaiFu\Code\ShenGu\KaoQinXiTong\Code\Tencent.DB\WxWorkSyncHelper.cs:line 187:

代码

 			var cacheUsers = _mysql.Wxuserdata.AsNoTracking().ToList();

                var UserInsert = wxGetUser.userlist?.Where(p =>
                {
                    if (!cacheUsers.Any(s => s.Userid == p.userid)) return true;
                    return false;
                }).ToList();

            
                var UserUpdate = wxGetUser.userlist?.Where(n =>
                {
                    if (cacheUsers.Any(s => s.Userid == n.userid && (s.Username != n.name || s.Slaves != n.alias))) return true;
                    return false;
                }).ToList();

              
                var UserDelete = cacheUsers.Where(p =>
                {
                    if (!wxGetUser.userlist.Any(s => s.userid == p.Userid)) return true;
                    return false;
                }).ToList();

                if (!UserInsert.IsNullModels())
                {
                    var users = new List<Wxuserdatum>();
                    foreach (var item in UserInsert)
                    {
                        var user = new Wxuserdatum()
                        {
                            Userid = item.userid,
                            Username = item.name,
                            Slaves = item.alias,
                            State = 1,
                            Creatime = DateTime.Now,
                            Changetime = DateTime.Now,
                        };
                        users.Add(user);
                    }
                    _mysql.Wxuserdata.AddRange(users);
                    _mysql.SaveChanges();
                }

                if (!UserUpdate.IsNullModels())
                {
                    var users = new List<Wxuserdatum>();
                    foreach (var item in UserUpdate)
                    {
                        var user = cacheUsers.FirstOrDefault(n => n.Userid == item.userid);
                        if (!user.IsNullModel())
                        {
                            user.Username = item.name;
                            user.Slaves = item.alias;
                            user.Changetime = DateTime.Now;
                            users.Add(user);
                        }
                    }
                    _mysql.Wxuserdata.UpdateRange(users);
                    _mysql.SaveChanges();
                }

                if (!UserDelete.IsNullModels())
                {
                    _mysql.Wxuserdata.RemoveRange(UserDelete);
                    _mysql.SaveChanges();
                }
笑叹、的主页 笑叹、 | 初学一级 | 园豆:34
提问于:2023-06-15 17:01
< >
分享
最佳答案
0

在Entity Framework Core中,即使在查询时使用了AsNoTracking()方法来禁用追踪功能,但在更新实体时仍然可能会遇到"tracked"相关错误。这是因为在更新实体时,EF Core仍然会尝试将实体对象附加到上下文中进行追踪,以便进行更改跟踪和保存。

  1. 使用Update()方法替代UpdateRange()方法:Update()方法只更新单个实体对象,而不会涉及到多个实体对象的批量更新。因此,使用Update()方法可能不会引发"tracked"相关错误。例如:
context.Update(entity);
  1. 使用Attach()方法显式附加实体对象:在使用UpdateRange()方法之前,先使用Attach()方法显式地将实体对象附加到上下文中,这样EF Core就不会尝试追踪已存在的实体对象。例如:
foreach (var entity in entities)
{
    context.Attach(entity);
}
context.UpdateRange(entities);
  1. 在更新之前使用Detach()方法将实体对象从上下文中分离:使用Detach()方法可以将实体对象从上下文中分离,这样EF Core就不会再追踪该实体对象。例如:
foreach (var entity in entities)
{
    context.Entry(entity).State = EntityState.Detached;
}
context.UpdateRange(entities);
收获园豆:5
lanedm | 老鸟四级 |园豆:2396 | 2023-06-16 08:31

这三种方式试了还是都不行0.0

笑叹、 | 园豆:34 (初学一级) | 2023-06-20 10:20

@笑叹、: 如果在使用上述方法后仍然遇到"tracked"相关错误,可能是因为实体对象的状态仍然被EF Core跟踪。在这种情况下,你可以尝试使用以下方法来解决问题:

  1. 使用Entry()方法将实体对象的状态设置为Detached
foreach (var entity in entities)
{
    context.Entry(entity).State = EntityState.Detached;
}
context.UpdateRange(entities);
  1. 使用DbContextChangeTracker属性来取消跟踪实体对象:
foreach (var entity in entities)
{
    context.ChangeTracker.Clear();
    context.Update(entity);
}
  1. 使用DbContextEntry()方法将实体对象的状态设置为Detached
foreach (var entity in entities)
{
    context.Entry(entity).State = EntityState.Detached;
    context.Update(entity);
}

请注意,以上方法中的entities是一个实体对象的集合,你需要根据你的实际情况将其替换为你要更新的实体对象集合。此外,你还需要确保在更新实体对象之前,实体对象的状态已经被设置为Detached,以避免"tracked"相关错误。

如果以上方法仍然无法解决问题,可能需要进一步检查你的代码逻辑和数据访问层的实现,以确定是否存在其他原因导致"tracked"相关错误的发生。

lanedm | 园豆:2396 (老鸟四级) | 2023-06-20 10:22

@lanedm: 跟踪实体状态都是Detached 1、3还是报错 2执行一条后 后面的更新都没实际生效

笑叹、 | 园豆:34 (初学一级) | 2023-06-20 10:39

@笑叹、: 1.使用AsNoTracking()方法之前,先调用AsNoTracking()方法,这样可以让EF Core在查询时不再对结果进行追踪。例如:
var query = context.Set<TEntity>().AsNoTracking().Select(x => x);
2.在使用UpdateRange()方法之前,先调用Change跟踪关闭方法,例如:
context.ChangeTracker.QueryCacheProfile = null;
3.在使用UpdateRange()方法之前,先清空EF Core的缓存,例如:
context.ChangeTracker.Entries().ToList().ForEach(x => x.State = EntityState.Detached);

lanedm | 园豆:2396 (老鸟四级) | 2023-06-20 10:42

@lanedm: 在foreach前加了 context.ChangeTracker.Clear(); 就可以了,感谢大佬
没搞懂AsNoTracking()为啥还是被跟踪了

笑叹、 | 园豆:34 (初学一级) | 2023-06-20 13:56
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册