2012-10-04 48 views
43

本來我認爲AsNoTracking()的全局設置?

context.Configuration.AutoDetectChangesEnabled = false; 

將禁用更改跟蹤。但不是。目前我需要在我所有的LINQ查詢中使用AsNoTracking()(對於我的只讀圖層)。是否有全局設置禁用DbContext上的跟蹤?

回答

14

由於此問題未使用特定的EF版本進行標記,因此我想提及在EF Core中的行爲可能是configured at the context level

您也可以在上下文 實例級別更改默認跟蹤行爲:

using (var context = new BloggingContext()) 
{ 
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 

    var blogs = context.Blogs.ToList(); 
} 
+0

你的鏈接告訴我錯誤 –

+0

@AliYousefie謝謝你,我修正了這個問題。 –

33

什麼根本上派生的背景下暴露的方法像這樣利用它進行查詢:

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

設置AsNoTracking全球範圍內是不可能的。您必須對每個查詢或每個ObjectSet(而不是DbSet)進行設置。後一種方法需要使用ObjectContext API。

var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; 
var set = objectContext.CreateObjectSet<T>(); 
set.MergeOption = MergeOption.NoTracking; 
// And use set for queries 
+1

會怎麼做一個在Entit之間加入是否只暴露像GetQuery 這樣的單個實體?感謝您的回覆。 – Vindberg

+0

你可以加入兩個不同'GetQuery'調用的結果 –

+0

它可能,但是我需要重做我的通用資源庫設置:/但是謝謝你的建議。 – Vindberg

2

你可以做這樣的事情在你的DbContext:

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

每當一個對象被你的情況下實現,它將被分離並不再跟蹤。

+0

我認爲這可行,但也許不是最好的方式來做到這一點。 AsNoTracking()據我所知不附加和分離對象。 –

+0

這裏的答案闡述了兩者之間的區別。 http://stackoverflow.com/a/20163424/219072這聽起來像AsNoTracking()絕對是首選的方法。 – emragins

2

更新:這並沒有真正的工作。看評論!

我討厭它,當我在StackOverflow上搜索時,答案是:「你不行!」或者「你可以,但前提是你完全改變了你曾經做過的每一個電話。」

反射任何人?我希望這將是一個DbContext設置。但既然不是這樣,我就用反思做了一個。

這個方便的小方法將在DbSet類型的所有屬性上設置AsNoTracking。

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); 
      } 
     } 
    } 

將其添加到重載的DbContext構造函數中。

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

它使用反射,這意味着有人會很快評論這是一個性能問題。但是,這真的是一個打擊?取決於你的用例。

+3

我還沒有測試過,但據我所知,'AsNoTracking()'只返回當前設置爲未跟蹤的'IQueryable'。在'DbSet'上調用它不會使下一個查詢未被跟蹤。我從這段代碼中得到的理解是,你在所有的集合上都調用了'AsNoTracking()',但是除非你使用返回的可查詢任何東西 – Jcl

+0

@Jcl,否則它不會做任何事情,我必須檢查它。它似乎在爲我工作。 – Rhyous

+1

我現在沒有時間來測試它,但乍一看對我來說很可疑。如果這樣做的話,這意味着只要你在上下文中的'DbSet'上調用'AsNoTracking()',那麼在同一個上下文中'DbSet'上的所有後續查詢都將不被跟蹤......而那個是一些奇怪的行爲(特別是考慮到沒有'AsTracking()'來補償)。如果這確實有效,我會說這是一個錯誤...或無證的功能:-) – Jcl

0

在我來說,因爲我需要的整個來龍去脈是隻讀的,而不是讀/寫。

所以我做了tt文件的更改,並更改了所有DbContext屬性以返回DbQuery而不是DbSet,從所有屬性中刪除了這些集合,並且爲get而返回了Model。AsNoTracking()

例如:

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

我在TT模板這樣做的方法是:

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)); 
 
    }