【问题标题】:Invalidating/Disabling Entity Framework cache使/禁用实体框架缓存
【发布时间】:2017-01-08 22:30:09
【问题描述】:

我看到有很多关于 EF 缓存的问题,但我还没有找到解决我的问题的方法。

直接的问题是

如何完全禁用 Entity Framework 6 缓存?或者,我可以以编程方式告诉 EF 忘记缓存,因为数据发生了问题吗?

背景

首先,我继承了一个由 EF(模型优先定义实体)和普通旧 SQL(操作数据)的奇怪混合组成的应用程序。我所做的是重构应用程序,以便:

  • 使用 EF6 LINQ 进行简单查询(例如 GetAll() 用于实体)
  • 将复杂的数据操作留在 SQL 中,在需要时使用 DbContext.Database.Connection
  • 添加 Spring.Web 支持以启用 DI 和事务(尚未)

目前,我已经重新组织了代码,以便应用程序的主要功能(在庞大的数据集上运行复杂的 SQL 查询)像以前一样工作,但是使用 as 可以更智能地完成查找域实体操作大多数 Entity Framework 尽可能

大多数....

我继承的其中一个页面是一个多复选框页面,我将向您展示以便更好地理解。我不会讨论前一个实现者的选择,因为修复我当前的问题并稍后重构代码比阻止开发一个损坏的功能更便宜。

这就是页面的样子

基本上Controller方法如下

    [HttpPost]
    public ActionResult Index(string[] codice, string[] flagpf, string[] flagpg, string[] flagammbce, string[] flagammdiv, string[] flagammest,
        string[] flagintab, string[] flagfinanz, string[] flagita, string[] flagest, string pNew){
            Sottogruppo2015Manager.ActivateFlagFor("pf", flagpf);
            Sottogruppo2015Manager.ActivateFlagFor("pg", flagpg);
            Sottogruppo2015Manager.ActivateFlagFor("ammbce", flagammbce);
            Sottogruppo2015Manager.ActivateFlagFor("ammdiv", flagammdiv);
            Sottogruppo2015Manager.ActivateFlagFor("ammest", flagammest);
            Sottogruppo2015Manager.ActivateFlagFor("intab", flagintab);
            Sottogruppo2015Manager.ActivateFlagFor("finanz", flagfinanz);
            Sottogruppo2015Manager.ActivateFlagFor("ita", flagita);
            Sottogruppo2015Manager.ActivateFlagFor("est", flagest);

            return RedirectToAction("Index", new { pNew });
 }

每个string[] 参数都是表中的一列。 ActivateFlagFor 方法依次运行两个查询

UPDATE table SET --param1-- = 0;
UPDATE table SET --param1-- = 1 where id in (--param2--)

当缓存启动时

以下是行为:

  • 我首先加载发出 LINQ 选择的页面:检查是否匹配列中的一和零
  • 我更改了一张或多张支票并提交
  • 控制器发出查询以更新数据库中的检查
  • 重定向(!表示新请求!)重新加载页面之前,我检查了数据库并应用了更改
  • 页面重新加载发出与上述相同的 LINQ 选择:显示旧检查

我确信这是一个缓存问题,因为重新加载应用程序可以解决问题。 由于应用程序的主要功能完全基于 SQL,因此对查找表的更改会反映到主要操作中,这是正确的行为。

我知道 EF 缓存对于性能来说是一项很棒的功能,但就我而言,我只是不想要它,至少在我将整个应用程序迁移到 LINQ DML 之前(可能是不可能的)。

我如何使用DbContext

当然,有些人可能会问“如何使用 DbContext?” “你的处理方法正确吗?”。

  • 我还没有在我的 Manager 类中集成 Spring 事务
  • 对数据库执行动作的每个对象都是I<Entity>Manager 扩展BaseManager
  • DbContext 是一个请求范围的 Spring 对象。我已经asked about disposing request-scoped objects,但我目前实施了一种解决方法,虽然不好,但在请求结束时正确处理 DbContext。

示例代码

public class ExampleManagerImpl : BaseManager, IExampleManager
{
    public void ActivateFlagFor(string aFlag, string[] aList)
    {
        string sql = "UPDATE table SET flag" + aFlag + " = 0";
        RunStatementV1(sql);

        if (aList != null && aList.Any())
        {
            sql = "UPDATE table SET flag" + aFlag + " = 1 WHERE id in (" + aList.ToCsvApex() + ")";
            RunStatementV1(sql);
        }
    }

    public IList<Models.Example> GetAll()
    {
        return DataContext.example.ToList(); //I don't dispose of the DataContext willingly
    }
}

public abstract class BaseManager {

    public DbContext DataContext { get; set; } //Autowired

    protected void RunStatementV1(string aSqlStatement)
    {
        IDbConnection connection = DataContext.Database.Connection;
        if (connection.State == ConnectionState.Closed || connection.State == ConnectionState.Broken) connection.Open(); //Needed because sometimes I found the connection closed, even if I don't dispose of it
        using (IDbCommand command = connection.CreateCommand())
        {
            command.CommandText = aSqlStatement;
            command.ExecuteNonQuery();
        }

    }
}

我尝试了什么

【问题讨论】:

    标签: c# linq entity-framework caching


    【解决方案1】:

    如果您想完全忽略 EF6 的缓存以进行数据检索,请将 AsNoTracking() 添加到查询的末尾(在调用 ToList() 或执行任何其他会执行查询的操作之前。

    MSDN on AsNoTracking()

    请注意,这样做既不会检查缓存中的现有数据,也不会将数据库调用的结果添加到缓存中。此外,Entity Framework 不会自动检测您从数​​据库中检索到的实体的更改。如果您确实想更改任何实体并将它们保存回数据库,则需要在调用 SaveChanges() 之前附加更改的实体。

    您目前的方法是:

    public IList<Models.Example> GetAll()
    {
        return DataContext.example.ToList();
    }
    

    它会变成:

    public IList<Models.Example> GetAll()
    {
        return DataContext.example.AsNoTracking().ToList();
    }
    

    如果您对处理 EF 缓存的其他选项感兴趣,我写了一个blog post about EF6 Cache Busting

    【讨论】:

    • AsNoTracking 并不总是好的,由于使用它,我有一个长期的尝试和搜索,因为例如,记录无法被删除
    • 让我添加任何对我不起作用的附加方式...您在此处引用 codethug.com/2016/02/19/Entity-Framework-Cache-Busting
    • @deadManN 如果您在这里打开一个新问题并链接到它,我很乐意帮助您调查它。但是如果没有任何细节,就很难知道如何解决您的问题。
    • 我在那个问题上改变了我的方式,并解决了它......只是路过并认为我应该说出来
    • @deadManN 你使用了哪种策略来禁用缓存?
    【解决方案2】:

    我也遇到过这个问题,但我可以解决它。

    我正在使用存储库模式并使用 .Net Core 的默认 DI。 我一直在使用 AddSingleton(...),但是与 DbContext 一起使用是错误的。

    因此,我已更改为 AddScoped,就像我从文档中读到的那样:Scoped 生命周期服务为每个请求创建一次。

    它解决了我的问题。

    You must read this section from ms docs: Service Lifetimes and Registration Options

    【讨论】:

    • 这对我帮助很大!
    猜你喜欢
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 2014-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多