Invalidating/Disabling Entity Framework 缓存
Invalidating/Disabling Entity Framework cache
我看到有很多关于 EF 缓存的问题,但我还没有找到解决问题的方法。
直接的问题是
如何完全禁用 Entity Framework 6 缓存?或者,我能否以编程方式告诉 EF 忘记缓存,因为数据发生了一些变化?
背景
首先,我继承了 一个由 EF(模型优先定义实体)和普通旧 SQL(操作数据)奇怪混合而成的应用程序.我所做的是重构应用程序以便:
- 使用 EF6 LINQ
进行简单查询(例如 GetAll()
查询实体)
- 在 SQL 中保留复杂的数据操作,需要时使用
DbContext.Database.Connection
- 添加
Spring.Web
支持以启用 DI 和事务(尚未)
目前,我已经重新组织了代码,以便应用程序的主要功能(运行 对庞大数据集的复杂 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--)
缓存启动时
行为如下:
- 我首先加载发出 LINQ 的页面 select:检查匹配列中的 1 和 0
- 我更改一张或多张支票并提交
- 控制器发出查询以更新数据库中的检查
- 在重定向(!意味着新请求!)重新加载页面之前,我检查了数据库并应用了更改
- 页面重新加载发出上面相同的 LINQ select:显示旧检查
我确定这是缓存问题,因为重新加载应用程序可以解决问题。
由于应用程序的主要功能完全基于 SQL,因此对查找 table 的更改会反映到主要操作中,这是正确的行为。
我知道 EF 缓存是提高性能的一项重要功能,但就我而言,我只是不想要它,至少在我将整个应用程序迁移到 LINQ DML 之前(可能是不可能的)。
我如何使用 DbContext
当然有些人可能会问 "how do you use your DbContext?" "do you dispose of it correctly?".
- 我还没有在我的管理器中集成 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();
}
}
}
我试过的
- How to stop entity framework caching : 禁用延迟加载无效
- :
Detach
似乎解决了问题,但我需要将其应用于许多实体,以便将来某一天恢复
如果您想完全忽略 EF6 的数据检索缓存,请将 AsNoTracking()
添加到查询的末尾(在调用 ToList()
或执行任何其他可执行查询的操作之前。
请注意,这样做既不会检查缓存中的现有数据,也不会将数据库调用的结果添加到缓存中。此外,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
我看到有很多关于 EF 缓存的问题,但我还没有找到解决问题的方法。
直接的问题是
如何完全禁用 Entity Framework 6 缓存?或者,我能否以编程方式告诉 EF 忘记缓存,因为数据发生了一些变化?
背景
首先,我继承了 一个由 EF(模型优先定义实体)和普通旧 SQL(操作数据)奇怪混合而成的应用程序.我所做的是重构应用程序以便:
- 使用 EF6 LINQ 进行简单查询(例如
- 在 SQL 中保留复杂的数据操作,需要时使用
DbContext.Database.Connection
- 添加
Spring.Web
支持以启用 DI 和事务(尚未)
GetAll()
查询实体)
目前,我已经重新组织了代码,以便应用程序的主要功能(运行 对庞大数据集的复杂 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--)
缓存启动时
行为如下:
- 我首先加载发出 LINQ 的页面 select:检查匹配列中的 1 和 0
- 我更改一张或多张支票并提交
- 控制器发出查询以更新数据库中的检查
- 在重定向(!意味着新请求!)重新加载页面之前,我检查了数据库并应用了更改
- 页面重新加载发出上面相同的 LINQ select:显示旧检查
我确定这是缓存问题,因为重新加载应用程序可以解决问题。 由于应用程序的主要功能完全基于 SQL,因此对查找 table 的更改会反映到主要操作中,这是正确的行为。
我知道 EF 缓存是提高性能的一项重要功能,但就我而言,我只是不想要它,至少在我将整个应用程序迁移到 LINQ DML 之前(可能是不可能的)。
我如何使用 DbContext
当然有些人可能会问 "how do you use your DbContext?" "do you dispose of it correctly?".
- 我还没有在我的管理器中集成 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();
}
}
}
我试过的
- How to stop entity framework caching : 禁用延迟加载无效
- :
Detach
似乎解决了问题,但我需要将其应用于许多实体,以便将来某一天恢复
如果您想完全忽略 EF6 的数据检索缓存,请将 AsNoTracking()
添加到查询的末尾(在调用 ToList()
或执行任何其他可执行查询的操作之前。
请注意,这样做既不会检查缓存中的现有数据,也不会将数据库调用的结果添加到缓存中。此外,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