C# 实体框架缓存问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15828811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 18:06:04  来源:igfitidea点击:

Entity Framework Caching Issue

c#asp.net-mvcentity-frameworkcatch-all

提问by Ramesh Rajendran

I am new to Entity Framework.

我是实体框架的新手。

I have get to some values in my database using EF. It returns perfectly, and the values are shown in labels. But When I delete all values in my table (without using EF), the EF query is returning my old values. I know the EF stores the values in cache and returns the cached data for subsequent runs. Is this correct?

我已经使用 EF 在我的数据库中获得了一些值。它完美返回,并且值显示在标签中。但是当我删除表中的所有值(不使用 EF)时,EF 查询将返回我的旧值。我知道 EF 将值存储在缓存中并为后续运行返回缓存数据。这样对吗?

So how can I solve the problem when I have deleted all values in my database, but EF returns the old values?

那么当我删除了数据库中的所有值,但 EF 返回旧值时,我该如何解决这个问题呢?

Edit:

编辑

Now i used datamodel.SaveChanges(). But now also it's returning the same old values.

现在我用了datamodel.SaveChanges()。但现在它也返回了相同的旧值。

My sample query is look like below:

我的示例查询如下所示:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.SaveChanges();
List<Compliance> compliance=new List<Compliance>();
IList<ComplianceModel> complianceModel;
if (HttpContext.Current.User.IsInRole("SuperAdmin"))
{
    compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
}

采纳答案by Dave Alperovich

If you know that changes happened outside of EF and want to refresh your ctxt for a specific entity, you can call ObjectContext.Refresh

如果您知道更改发生在 EF 之外并希望为特定实体刷新您的 ctxt,您可以调用ObjectContext.Refresh

datamodel.Refresh(RefreshMode.StoreWins, orders);

If this seems like it will be a common occurance, you should disable object caching in your queries:

如果这看起来很常见,您应该在查询中禁用对象缓存:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.tblCities.MergeOption = MergeOption.NoTracking; 

or for to turn off object level caching for specific Entity,

或关闭特定实体的对象级缓存,

Context.Set<Compliances>().AsNoTracking();

回答by Akash Kava

EF will not load changes unless you re query the context. EF queries db and loads maps them into objects, it watches changes you perform on objects and not on the database. EF does not track changes made directly to database and it will never track.

除非您重新查询上下文,否则 EF 不会加载更改。EF 查询 db 并将它们映射到对象中,它会监视您对对象而不是数据库执行的更改。EF 不跟踪直接对数据库所做的更改,它永远不会跟踪。

You have loaded a List, that List is your cache in memory. Even calling Save Changes will not refresh. You will have to query the context once again, that is create new list.

您已经加载了一个列表,该列表是您在内存中的缓存。即使调用 Save Changes 也不会刷新。您将不得不再次查询上下文,即创建新列表。

To see changes You will have to execute following line once more,

要查看更改,您必须再次执行以下行,

datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList()

回答by Morteza

When you use EF it by default loads each entity only once per context. The first query creates entity instace and stores it internally. Any subsequent query which requires entity with the same key returns this stored instance. If values in the data store changed you still receive the entity with values from the initial query

当您使用 EF 时,默认情况下,每个上下文仅加载每个实体一次。第一个查询创建实体实例并将其存储在内部。任何需要具有相同键的实体的后续查询都会返回此存储的实例。如果数据存储中的值发生更改,您仍然会收到带有初始查询值的实体

A careful answer:

认真回答:

https://stackoverflow.com/a/3653392/1863179

https://stackoverflow.com/a/3653392/1863179

回答by HGMamaci

Below code helped my object to be refreshed with fresh database values. The Entry(object).Reload() command forces the object to recall database values

下面的代码帮助我的对象用新的数据库值刷新。Entry(object).Reload() 命令强制对象调用数据库值

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();

回答by Tiago Gouvêa

I recommend you to use some MergeOption to all EntitieSet after create the context, like this:

我建议您在创建上下文后对所有 EntitieSet 使用一些 MergeOption,如下所示:

var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>));
foreach (PropertyInfo objSetProp in objSetProps)
{
    ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null);
    objSet.MergeOption = MergeOption.PreserveChanges;
}

Read about the MergeOption here: http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspxYour will use NoTracking, I think.

在此处阅读有关 MergeOption 的信息:http: //msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx我认为您将使用 NoTracking。

If you want to CLEAR the "cached" entities, detaching it.

如果要清除“缓存”实体,请将其分离。

var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
foreach (var objectStateEntry in entidades)
    Ctx.Detach(objectStateEntry.Entity);

Where Ctx are my Context.

Ctx 是我的上下文。

回答by Brian from state farm

Firstly I would not suggest modifying the database external to your system unless you are only doing testing and development.

首先,除非您仅进行测试和开发,否则我不建议修改系统外部的数据库。

The EF DbContext contains an IDisposable interface. To release any cached data either make the Dispose calls manually or place your Database Object inside a using block.

EF DbContext 包含一个 IDisposable 接口。要释放任何缓存数据,请手动调用 Dispose 或将数据库对象放在 using 块中。

        using (SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities())
        {
            List<Compliance> compliance = new List<Compliance>();
            IList<ComplianceModel> complianceModel;
            if (HttpContext.Current.User.IsInRole("SuperAdmin"))
            {
                compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
            }
        }

This will make sure the context is cleared and recreated the next time it is used. Make sure to do this for all your calls and not just the one you are having issues with.

这将确保上下文被清除并在下次使用时重新创建。确保对您的所有电话都执行此操作,而不仅仅是您遇到问题的电话。

回答by Colin

I suspect that the underlying problem here is that your DbContextis hanging around too long. I can tell from the fact that you are using HttpContextthat you have a web application, and General guidelines when working with DbContextinclude

我怀疑这里的潜在问题是你待的DbContext时间太长了。我可以从您使用的事实中HttpContext看出您有一个 Web 应用程序,并且使用 DbContext 时的一般准则包括

When working with Web applications, use a context instance per request.

使用 Web 应用程序时,请为每个请求使用一个上下文实例。

If you are using MVC you could use the Dispose pattern in your controller like this:

如果您使用的是 MVC,您可以在控制器中使用 Dispose 模式,如下所示:

public class EmployeeController : Controller
{
    private EmployeeContext _context;

    public EmployeeController()
    {
        _context = new EmployeeContext();
    }

    public ActionResult Index()
    {
        return View(_context.Employees.ToList());
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _context.Dispose();
        }
        base.Dispose(disposing);
    }
}

But you really ought to be looking at dependency injection to manage the DbContext lifetime

但是你真的应该考虑依赖注入来管理 DbContext 生命周期

回答by Marc Johnston

Couple things you can do.

你可以做几件事。

  1. Use a new context. The cached entities are stored in the context. Using a new context prevents it from using the cache.
  2. If you really want a global/long lasting context, you have two sub options: a.) always call the Reload method. db.Entry(entity).Reload() ... this forces the context to reload that entity. b.) use a SqlDependency object to detect when records change and reload the entities as needed. https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3
  1. 使用新的上下文。缓存的实体存储在上下文中。使用新上下文可防止其使用缓存。
  2. 如果你真的想要一个全局/持久的上下文,你有两个子选项:a.) 总是调用 Reload 方法。db.Entry(entity).Reload() ... 这会强制上下文重新加载该实体。b.) 使用 SqlDependency 对象来检测记录何时更改并根据需要重新加载实体。 https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3

回答by Adil Mammadov

I think what you need is GetDatabaseValues(). It is used like:

我认为你需要的是GetDatabaseValues(). 它的用法如下:

context.Entry(/*your entry*/).GetDatabaseValues();

Information below is from msdn:

以下信息来自msdn

The current values are the values that the properties of the entity currently contain. The original values are the values that were read from the database when the entity was queried. The database values are the values as they are currently stored in the database. Getting the database values is useful when the values in the database may have changed since the entity was queried such as when a concurrent edit to the database has been made by another user.

当前值是实体的属性当前包含的值。原始值是查询实体时从数据库中读取的值。数据库值是它们当前存储在数据库中的值。当数据库中的值自查询实体后可能已更改时,获取数据库值非常有用,例如当另一个用户对数据库进行并发编辑时。

回答by David Sherret

I think you should follow some of the other solutions here, but it seems like you're wanting to clear the cache. You can achieve this by doing the following:

我认为您应该在这里遵循一些其他解决方案,但您似乎想要清除缓存。您可以通过执行以下操作来实现此目的:

var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30)

datamodel.Compliances.Local.ToList().ForEach(c => {
    datamodel.Entry(c).State = EntityState.Detached;
});

count = datamodel.Compliances.Local.Count; // 0