2012-10-04 11 views
43

は、もともと私はAsNoTracking()のグローバル設定?

context.Configuration.AutoDetectChangesEnabled = false; 

は、変更の追跡を無効にすると信じていました。しかし、いいえ。現在、すべてのLINQクエリ(私の読み取り専用レイヤー)でAsNoTracking()を使用する必要があります。 DbContextでの追跡を無効にするグローバル設定はありますか?単にあなたの派生文脈上、このような方法を暴露し、クエリのためにそれを使用について

答えて

14

この質問は特定のEFバージョンでタグ付けされていないので、私はEFコアでその動作がconfigured at the context levelであることを言及したいと思います。

また、コンテキスト インスタンス・レベルでのデフォルトの追跡動作を変更することができます。私の場合は

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

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

あなたのリンクは私にエラーを表示する –

+0

@AliYousefieありがとう、私はそれを修正しました。 –

33

何:AsNoTrackingの設定

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

が世界的に不可能です。クエリごとに、またはObjectSetDbSetではなく)ごとに設定する必要があります。後者の方法では、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

あなたは2つの異なる 'GetQuery'呼び出しの結果に参加することができます –

+0

可能ですが、次に私はジェネリックリポジトリの設定をやり直す必要があります。 – Vindberg

2

あなたはDbContextにこのような何かを行うことができます:

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

オブジェクトがあなたのコンテキストでマテリアライズされるたびに、それが切り離され、もはや追跡されます。

+0

これはうまくいくと思いますが、これを行うには最良の方法ではないかもしれません。 AsNoTracking()は、私が知っている限り、オブジェクトをAttach and Detachしません。 –

+0

ここでの答えは、2つの違いを詳しく説明しています。 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ファイルに変更を加え、DbSetではなくDbQueryを返すようにすべてのDbContextプロパティを変更し、すべてのプロパティからセットを削除し、取得のためにモデルを返しました。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)); 
 
    }

関連する問題