如何在EF 4.1 RC中的DbContext级别关闭更改跟踪? [英] How do I turn off change tracking at the DbContext level in EF 4.1 RC?

查看:264
本文介绍了如何在EF 4.1 RC中的DbContext级别关闭更改跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个常见的问题:我正在更新数据库中的值,但EF使用其原始的内存副本,而这些更改的值不会反映在显示的数据中。我明白为什么会这样,但是我无法想像出来。



最常见的解决方案似乎是设置 MergeOptions。 NoTracking 完全关闭更改跟踪(或查询时使用 AsNoTracking()扩展方法),并在每次访问对象时强制刷新,这对我的目的是很好的。



我有一个通用的基础存储库,我的其他存储库继承自:

  public abstract class RepositoryBase< T>其中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;
}

//其他一些IQueryable方法(Query,GetByProductCode等)

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

而一个 DbContext 这样:

  public class Db:DbContext 
{
private IDbSet< Product> ; _产品展示;

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

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

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

如果我更改了全部()我的存储库的方法因此:

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

我得到所需的结果 - 数据库中的更新反映在页面展示产品的刷新。但是,我不能在 Get()方法中执行此操作,因为该扩展方法仅适用于 IQueryable



理想情况下,我想将其关闭在 DbContext 级别,因为我永远不会需要更改跟踪,但是似乎并没有一个明显的方法,而且关于这个问题的文档几乎没有零(除非有人可以指出我一些,请!)。



我尝试向 DbContext 添加一个构造函数,禁用这些配置选项:

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

但我必须承认我只是猜测他们真正做什么我只是通过查看源代码找到他们),而且他们似乎没有任何效果。



任何帮助将不胜感激。如果更多的信息/代码会有帮助,请让我知道。

解决方案

如果你想强制上下文每次获取新的数据您不想使用查找方法。 查找方法始终先查询内部存储。使用这个代替:

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

但是我不明白你需要什么?你的意思是:


当显示产品
的页面是数据库中的一个更新被反映为
刷新


上下文是工作单位。它应该用作工作单位 - 在Web应用程序或Web服务中,这意味着每个请求创建新的上下文实例。在winforms / wpf应用程序中,它意味着每个逻辑块使用上下文(每个演示者等)。因为这样,您只需要在非常具体的情况下才需要它,但是您希望在全球范围内。您的描述看起来像您正在完全不好的解决方案。在每个请求的重新创建上下文中都没有性能成本。


I've encountered what seems to be a common problem: I am updating values in my database, but EF is using its original in-memory copy of the object and these changed values are not reflected in the displayed data. I understand why this is, but I can't figure out a way around it.

The most common solution seems to be to set MergeOptions.NoTracking to turn off change tracking completely (or use the AsNoTracking() extension method when querying) and force a refresh every time the object is accessed, which is fine for my purposes.

I've got a generic base repository which my other repositories inherit from:

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);
    }
}    

And a DbContext like this:

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();
    }
}

If I change the All() method of my repository thus:

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

I get the desired result - an update in the database is reflected when the page displaying the products is refreshed. However, I can't do this in the Get() method, as that extension method only works on an IQueryable.

Ideally I'd like to turn this off at the DbContext level as I will never need change tracking, but there doesn't seem to be an obvious way to do this, and there is pretty much zero documentation on the subject (unless someone can point me to some? Please!).

I tried adding a constructor to the DbContext with these configuration options disabled:

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

But I must admit I'm only guessing as to what they really do (I only found them through looking at the source code), and they don't seem to have any effect anyway.

Any help would be greatly appreciated. If more info/code would help, please let me know.

解决方案

If you want to force context to get fresh data each time you don't want to use Find method. Find method always query internal storage first. Use this instead:

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

But I don't understand what do you need this? What do you mean by:

an update in the database is reflected when the page displaying the products is refreshed

Context is unit of work. It should be used as unit of work - in web application or web service it means creating new context instance per request. In winforms / wpf application it means using context per logical block (per presenter etc). Because of that you should need this only in very specific scenarios but you want it globally. Your description seems like you are reusing context among requests which is completely bad solution. There are no performance costs in recreating context for each request.

这篇关于如何在EF 4.1 RC中的DbContext级别关闭更改跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆