EntityFrameworkCore 跟踪 NoTrackingBehavior 的变化 [英] EntityFrameworkCore tracks changes on NoTrackingBehavior

查看:27
本文介绍了EntityFrameworkCore 跟踪 NoTrackingBehavior 的变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MyContext.cs

MyContext.cs

public class MyContext: DbContext
{
    public MyContext(DbContextOptions<DBContext> options) : base(options)
    {
        ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        ChangeTracker.LazyLoadingEnabled = false;
        ChangeTracker.AutoDetectChangesEnabled = false;
        this.Database.EnsureCreated();
    }
}

BaseRepository.cs

BaseRepository.cs

 public abstract class BaseRepository<TDBEntity> where TDBEntity : class, new()
 {
        protected readonly MyContext dbContext;

        public BaseRepository(MyContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public virtual void Update(TDBEntity model)
        {
            dbContext.Entry(model).State = EntityState.Modified;
        }

        public Task CommitAsync()
        {
            return dbContext.SaveChangesAsync();
        }
  }  

如果我更新同一个实体两次,我会得到以下错误:

If I update the same entity two times, I will get the following error:

 The instance of entity type 'Foobar' 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.

我处于连接的 DbContext 场景"中,但我不想要任何跟踪行为.我想使用 EntityFrameworkCore 来仅"生成 SQL 语句.

I am on a 'connected DbContext scenario' but I don't want any tracking behaviour. I want to use EntityFrameworkCore for 'just' generating SQL-Statements.

推荐答案

嗯,这是一件棘手的事情.我已经调试了几个小时的 EF Core 源以找到更好的方法,但没有运气.ChangeTracker 通过引用搜索EntityEntry 的问题.如果未通过引用找到,则按实体键搜索,如果找到条目 - 您有此例外.

Well, it is a tricky thing. I have debugged EF Core sources for several hours to find better way, but with no luck. Problem that ChangeTracker searches for EntityEntry by the reference. If not found by reference it searches by entity keys and if entry found - you have this exception.

于是,这些扩展方法就诞生了.即使使用 Internals 也不是非常有效,但它展示了如何做到这一点.

So, these extension methods are born. Not super effective even using Internals, but it shows how to do that.

public static class ChangeTrackerExtensions
{
    public static EntityEntry<T> GetEntry<T>(this DbContext ctx, T entity, out bool isNew) where T : class
    {
        var entityType = ctx.Model.FindEntityType(typeof(T));
        var stateManager = ctx.GetService<IStateManager>();

        isNew = false;
        foreach (var key in entityType.GetKeys())
        {
            var keyArray = key.Properties
                .Where(p => p.PropertyInfo != null || p.FieldInfo != null)
                .Select(p =>
                    p.PropertyInfo != null
                        ? p.PropertyInfo.GetValue(entity)
                        : p.FieldInfo.GetValue(entity)).ToArray();

            if (keyArray.Length == key.Properties.Count)
            {
                var entry = stateManager.TryGetEntry(key, keyArray);

                if (entry != null)
                {
                    return ctx.Entry((T)entry.Entity);
                }
            }
        }

        isNew = true;
        var newEntry = ctx.Entry(entity);

        return newEntry;
    }

    public static EntityEntry<T> UpdateEntry<T>(this DbContext ctx, T entity) where T : class
    {
        bool isNew;
        var entry = ctx.GetEntry(entity, out isNew);

        if (isNew)
        {
            entry.State = EntityState.Modified;
        }
        else
        {
            entry.CurrentValues.SetValues(entry);
        }
        return entry;
    }
}

所以,在你的情况下更新应该看起来像

So, update in your case should looks like

   public virtual void Update(TDBEntity model)
   {
       dbContext.UpdateEntry(model);
   }

这篇关于EntityFrameworkCore 跟踪 NoTrackingBehavior 的变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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