Глобальная настройка для AsNoTracking()?
Первоначально я считал, что
context.Configuration.AutoDetectChangesEnabled = false;
отключит отслеживание изменений. Но нет. В настоящее время мне нужно использовать AsNoTracking()
для всех моих запросов LINQ (для моего слоя только для чтения). Есть ли глобальная настройка для отключения отслеживания в DbContext?
Ответы
Ответ 1
Поскольку этот вопрос не помечен конкретной версией EF, я хотел бы упомянуть, что в EF Core поведение может быть настроено на уровне контекста.
Вы также можете изменить поведение отслеживания по умолчанию в контексте уровень экземпляра:
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
Ответ 2
Как просто выставлять такой метод в вашем производном контексте и использовать его для запросов:
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
Ответ 3
Вы можете сделать что-то подобное в своем DbContext:
public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
{
Entry(e.Entity).State = EntityState.Detached;
}
Каждый раз, когда объект материализуется в вашем контексте, он будет отсоединен и больше не будет отслеживаться.
Ответ 4
Обновление: на самом деле это не работает. См. Комментарии!
Я ненавижу, когда я ищу в StackOverflow, и ответ: "Вы не можете!" или "Вы могли бы, но только если вы полностью измените каждый звонок, который вы когда-либо делали".
Отразить кого-нибудь? Я надеялся, что это будет установка DbContext. Но так как это не так, я сделал один, используя отражение.
Этот удобный метод будет устанавливать AsNoTracking для всех свойств типа 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);
}
}
}
Добавьте его в перегруженный конструктор DbContext.
public ActivationDbContext(bool proxyCreationEnabled, bool lazyLoadingEnabled = true, bool asNoTracking = true)
{
Configuration.ProxyCreationEnabled = proxyCreationEnabled;
Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
if (asNoTracking)
GloballySetAsNoTracking();
}
Он использует отражение, что означает, что кто-то быстро прокомментирует, что это удар производительности. Но действительно ли это большая часть хита? Зависит от вашего варианта использования.
Ответ 5
В моем случае, поскольку мне нужен весь контекст для чтения, а не для чтения/записи.
Итак, я сделал изменения в файле tt и изменил все свойства DbContext, чтобы вернуть DbQuery вместо DbSet, удалил наборы из всех свойств, а для получателей я возвратил Model.AsNoTracking()
Например:
public virtual DbQuery<Campaign> Campaigns { get{ return Set<Campaign>().AsNoTracking();} }