Подтвердить что ты не робот

Глобальная настройка для AsNoTracking()?

Первоначально я считал, что

context.Configuration.AutoDetectChangesEnabled = false;

отключит отслеживание изменений. Но нет. В настоящее время мне нужно использовать AsNoTracking() для всех моих запросов LINQ (для моего слоя только для чтения). Есть ли глобальная настройка для отключения отслеживания в DbContext?

4b9b3361

Ответ 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();} }