Global setting for AsNoTracking ()?

I originally believed that

context.Configuration.AutoDetectChangesEnabled = false; 

disable change tracking. But no. Currently I need to use AsNoTracking() for all my LINQ queries (for my read-only layer). Is there a global setting to disable tracking in DbContext?

+42
entity-framework change-tracking
04 Oct
source share
5 answers

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

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

 using (var context = new BloggingContext()) { context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var blogs = context.Blogs.ToList(); } 
+11
01 Oct '16 at 17:15
source share

How to simply expose such a method in your derived context and use it for queries:

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

Configuring AsNoTracking globally is not possible. You must set it for each request or for each ObjectSet (not a DbSet ). The latter approach requires the use of the ObjectContext API.

 var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; var set = objectContext.CreateObjectSet<T>(); set.MergeOption = MergeOption.NoTracking; // And use set for queries 
+33
04 Oct
source share

You can do something like this in your DbContext:

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

Each time an object materializes in your context, it will be disconnected and will no longer be tracked.

+2
Mar 16 '15 at
source share

Update: This does not actually 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 call you ever made."

Repel someone? I was hoping this would be a DbContext installation. But since it is not, I made one using reflection.

This convenient method will set AsNoTracking for 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 the 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 that someone will quickly comment that this is a performance hit. But is this really a big hit? Depends on your use case.

+2
Nov 25 '15 at 21:05
source share

In my case, since I need the whole context to read, not read / write.

So, I made changes to the tt file and changed all the DbContext properties to return DbQuery instead of DbSet, removed the sets from all the properties, and for the recipients I returned Model.AsNoTracking ()

For example:

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

How I did this in the tt template:

 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
Jan 05 '17 at 0:43
source share



All Articles