我看到有很多关于EF缓存的问题,但是对于我的问题还没有找到解决方案。
直接问题是
如何完全禁用Entity Framework 6缓存?或者,我能否以编程方式告诉EF忘记缓存,因为数据发生了某些变化?
背景
首先,我继承了一个应用程序,它由EF(使用模型优先定义实体)和纯旧SQL(用于操作数据)的奇怪混合构成。我的做法是重构应用程序,以便:
- 使简单查询(例如
GetAll()
)使用EF6 LINQ - 将复杂的数据操作留在SQL中,需要时使用
DbContext.Database.Connection
- 添加
Spring.Web
支持以启用DI和事务(尚未完成)
当前,我已经重新组织了代码,使应用程序的主要功能(在大型数据集上运行复杂的SQL查询)与之前相同,但查找域实体的操作使用尽可能多的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选择来加载页面:检查匹配列中的一和零
- 我更改一个或多个检查并提交
- 控制器发出查询以更新DB中的检查
- 重定向(!表示新请求!)重新加载页面之前,我会检查DB,更改已应用
- 页面重新加载,发出与上述相同的LINQ选择:旧检查显示
我确定这是一个缓存问题,因为重新加载应用程序可以解决问题。 由于应用程序的主要功能完全基于SQL,因此对查找表进行的更改会反映在主要操作中,这是正确的行为。
我知道EF缓存是性能的一个很好的特性,但在我的情况下,我只是不想要它,至少在我将整个应用程序迁移到LINQ DML之前(可能不可能)。
如何使用DbContext
当然,你们中的一些人可能会问“你如何使用你的DbContext?”“你是否正确地处理了它?”。
- 我还没有在我的Manager类中集成Spring事务
- 每个在数据库上执行操作的对象都是扩展
BaseManager
的I<Entity>Manager
DbContext
是一个请求范围的Spring对象。我已经询问了如何处理请求范围的对象,但目前我实现了一个解决方法,虽然不好,但可以在请求结束时正确地处理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();
}
}
}
我尝试了什么
- 如何停止实体框架缓存:禁用延迟加载无效
- https://dev59.com/lWUo5IYBdhLWcg3wtRQx#22818783:
Detach
似乎可以解决问题,但我需要将其应用于数十个实体,以便在未来某个时候恢复
AsNoTracking
,因为我需要更新实体,我也不能使用新的DbContext,因为有一些架构设计上的要求,而Detach解决方案则需要每次都应用,这对我来说会很繁琐。 那么,UseMemoryCache方法能帮助我解决问题吗? - Hakan Fıstık