Как отключить отслеживание изменений на уровне DbContext в EF 4.1 RC? - PullRequest
7 голосов
/ 31 марта 2011

Я столкнулся с общей проблемой: я обновляю значения в своей базе данных, но EF использует свою оригинальную копию объекта в памяти, и эти измененные значения не отражаются в отображаемых данных. Я понимаю, почему это так, но я не могу найти способ обойти это.

Наиболее распространенным решением, по-видимому, является установка MergeOptions.NoTracking для полного отключения отслеживания изменений (или использования метода расширения AsNoTracking() при запросах) и принудительного обновления при каждом доступе к объекту, что хорошо для моих целей .

У меня есть общий базовый репозиторий, от которого наследуются мои другие репозитории:

public abstract class RepositoryBase<T> where T : class
{
    private readonly IDbSet<T> _dbset;
    private readonly IUnitOfWork _unitOfWork;

    protected RepositoryBase(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
        _dbset = _unitOfWork.Database.Set<T>();
    }

    public virtual IQueryable<T> All()
    {
        return _dbset;
    }

    // Some other IQueryable methods here (Query, GetByProductCode etc)

    public virtual T Get(long id)
    {
        return _dbset.Find(id);
    }
}    

А DbContext вот так:

public class Db : DbContext
{
    private IDbSet<Product> _products;

    public IDbSet<Product> Products
    {
        get { return _products ?? (_products = DbSet<Product>()); }
    }

    public virtual IDbSet<T> DbSet<T>() where T : class
    {
        return Set<T>();
    }

    public virtual void Commit()
    {
        base.SaveChanges();
    }
}

Если я изменю All() метод моего хранилища таким образом:

public virtual IQueryable<T> All()
{
    return _dbset.AsNoTracking();
}

Я получаю желаемый результат - обновление в базе данных отражается при обновлении страницы, отображающей товары. Однако я не могу сделать это в методе Get(), так как этот метод расширения работает только на IQueryable.

В идеале я хотел бы отключить это на уровне DbContext, так как мне никогда не понадобится отслеживание изменений, но, кажется, не существует очевидного способа сделать это, и документации по предмет (разве кто-то может указать мне на некоторых? Пожалуйста!).

Я попытался добавить конструктор в DbContext с отключенными параметрами конфигурации:

public Db()
{
    base.Configuration.ProxyCreationEnabled = false;
    base.Configuration.AutoDetectChangesEnabled = false;
}

Но я должен признать, что я только догадываюсь о том, что они действительно делают (я нашел их только при просмотре исходного кода), и, похоже, они в любом случае не оказывают никакого влияния.

Любая помощь будет принята с благодарностью. Если вам нужна дополнительная информация / код, пожалуйста, дайте мне знать.

1 Ответ

6 голосов
/ 31 марта 2011

Если вы хотите, чтобы контекст получал свежие данные каждый раз, когда вы не хотите использовать метод Find.Find метод всегда сначала запрашивает внутреннее хранилище.Используйте это вместо:

public virtual T Get(long id)
{
    return All().SingleOrDefault(e => e.Id == id);
}

Но я не понимаю, зачем вам это?Что вы подразумеваете под:

обновление в базе данных отражается при обновлении страницы, отображающей продукты

Контекст - это единица работы.Он должен использоваться как единица работы - в веб-приложении или веб-сервисе это означает создание нового экземпляра контекста для каждого запроса.В приложении winforms / wpf это означает использование контекста на логический блок (на докладчика и т. Д.).Из-за этого вам это нужно только в очень специфических сценариях, но вы хотите это глобально.Ваше описание выглядит так, как будто вы повторно используете контекст среди запросов, что является совершенно плохим решением .Для каждого запроса нет затрат на производительность при воссоздании контекста.

...