Global setting for AsNoTracking()?

前端 未结 6 1576
礼貌的吻别
礼貌的吻别 2020-11-27 17:30

Originally I believed that

context.Configuration.AutoDetectChangesEnabled = false;

would disable change tracking. But no. Cur

相关标签:
6条回答
  • 2020-11-27 17:49

    Since this question is not tagged with a specific EF version, I wanted to mention that in EF Core the behavior can be configured at the context level.

    You can also change the default tracking behavior at the context instance level:

    using (var context = new BloggingContext())
    {
        context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    
        var blogs = context.Blogs.ToList();
    }
    
    0 讨论(0)
  • 2020-11-27 17:49

    What about simply exposing method like this on your derived context and use it for queries:

    public IQueryable<T> GetQuery<T>() where T : class {
        return this.Set<T>().AsNoTracking();
    }
    

    Setting AsNoTracking globally is not possible. You must set it per each query or per each ObjectSet (not DbSet). The latter approach requires using ObjectContext API.

    var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
    var set = objectContext.CreateObjectSet<T>();
    set.MergeOption = MergeOption.NoTracking;
    // And use set for queries
    
    0 讨论(0)
  • 2020-11-27 17:49

    In my case since I needed the whole context to be readonly rather than Read/Write.

    So I did a change to the tt file, and changed all the DbContext properties to return DbQuery instead of DbSet, removed the sets from all properties, and for the gets, I returned the Model.AsNoTracking()

    For example:

    public virtual DbQuery<Campaign> Campaigns { get{ return Set<Campaign>().AsNoTracking();} }

    The way I did this in the tt template is:

    public string DbQuery(EntitySet entitySet)
        {
            return string.Format(
                CultureInfo.InvariantCulture,
                "{0} virtual DbQuery<{1}> {2} {{ get{{ return Set<{1}>().AsNoTracking();}} }}",
                Accessibility.ForReadOnlyProperty(entitySet),
                _typeMapper.GetTypeName(entitySet.ElementType),
                _code.Escape(entitySet));
        }

    0 讨论(0)
  • 2020-11-27 17:50

    You could do something like this in your DbContext:

    public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
    {
        Entry(e.Entity).State = EntityState.Detached;
    }
    

    Every time an object is materialized by your context, it will be detached and no longer tracked.

    0 讨论(0)
  • 2020-11-27 18:07

    Update: This didn't really work. See comments!

    I hate it when I search on StackOverflow and the answer is: "You can't!" or "You could, but only if you completely change every single call you've ever made."

    Reflection anyone? I was hoping this would be a DbContext setting. But since it is not, I made one using reflection.

    This handy little method will set AsNoTracking on all properties of type DbSet.

        private void GloballySetAsNoTracking()
        {
            var dbSetProperties = GetType().GetProperties();
            foreach (PropertyInfo pi in dbSetProperties)
            {
                var obj = pi.GetValue(this, null);
                if (obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(DbSet<>))
                {
                    var mi = obj.GetType().GetMethod("AsNoTracking");
                    mi.Invoke(obj, null);
                }
            }
        }
    

    Add it to an overloaded DbContext constructor.

        public ActivationDbContext(bool proxyCreationEnabled, bool lazyLoadingEnabled = true, bool asNoTracking = true)
        {
            Configuration.ProxyCreationEnabled = proxyCreationEnabled;
            Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
            if (asNoTracking)
                GloballySetAsNoTracking();
        }
    

    It uses reflection, which means someone will quickly comment that this is a performance hit. But is it really that much of a hit? Depends on your use case.

    0 讨论(0)
  • 2020-11-27 18:11

    In EntityFramework.Core it is very easy.

    For this purpose you can use UseQueryTrackingBehavior method.

    Code snippet is here:

    services.AddDbContext<DatabaseContext>(options =>
    {
        options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        options.UseSqlServer(databaseSettings.DefaultConnection);
    });
    
    0 讨论(0)
提交回复
热议问题