Invalidating/Disabling Entity Framework 缓存

Invalidating/Disabling Entity Framework cache

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

直接的问题是

如何完全禁用 Entity Framework 6 缓存?或者,我能否以编程方式告诉 EF 忘记缓存,因为数据发生了一些变化?

背景

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

目前,我已经重新组织了代码,以便应用程序的主要功能(运行 对庞大数据集的复杂 SQL 查询)像以前一样工作,但随后查找域使用 as most Entity Framework as possible

可以更智能地完成实体操作

最...

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

页面是这样的

基本上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[] 参数是 table 中的一列。 ActivateFlagFor 方法按顺序运行两个查询

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

缓存启动时

行为如下:

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

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

我如何使用 DbContext

当然有些人可能会问 "how do you use your DbContext?" "do you dispose of it correctly?".

示例代码

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

    }
}

我试过的

如果您想完全忽略 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

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

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

所以,我已经更改为 AddScoped,就像我从文档中读到的那样:Scoped lifetime services are created once per request.

解决了我的问题

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