もともと私は
_context.Configuration.AutoDetectChangesEnabled = false;
_
変更の追跡を無効にします。しかし、違います。現在、すべてのLINQクエリでAsNoTracking()
を使用する必要があります(読み取り専用レイヤー用)。 DbContextで追跡を無効にするグローバル設定はありますか?
この質問には特定のEFバージョンがタグ付けされていないため、EF Coreで動作を コンテキストで設定可能)レベル 。
コンテキストインスタンスレベルでデフォルトの追跡動作を変更することもできます。
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
派生コンテキストでこのようなメソッドを単純に公開し、クエリに使用するとどうなりますか?
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
DbContextで次のようなことができます。
public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
{
Entry(e.Entity).State = EntityState.Detached;
}
オブジェクトがコンテキストによって具体化されるたびに、オブジェクトは切り離され、追跡されなくなります。
更新:これは実際には機能しませんでした。コメントをご覧ください!
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();
}
これはリフレクションを使用します。つまり、誰かがこれがパフォーマンスヒットであることをすばやくコメントします。しかし、それは本当に大ヒットですか?ユースケースに依存します。
私の場合、コンテキスト全体を読み取り/書き込みではなく読み取り専用にする必要がありました。
そのため、ttファイルを変更し、DbContextのすべてのプロパティを変更してDbSetではなくDbQueryを返し、すべてのプロパティからセットを削除し、取得のために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));
}