返回旧数据的实体框架
本文关键字:实体 框架 数据 返回 | 更新日期: 2023-09-27 17:55:08
我遇到了 EF 在 3 层 WPF 应用程序中不返回最新数据的问题,我怀疑这与我如何处理上下文的生存期有关。这是场景:
有几个存储库包装在一个工作单元中。还有一个服务(MyService),它使用UnitOfWork。还必须直接从 UI 调用此工作单元,而无需通过服务。
在主窗口的 ViewModel 中,我创建一个新窗口(首先使用 ViewModel):
var dialog = new DialogViewModel(_eventAggregator, _unitOfWork, Container.Resolve<CarService>());
此主窗口 ViewModel 有一个 UnitOfWork,它已注入到构造函数中,并传递给 DialogViewModel。
CarService 的构造函数还需要一个 UnitOfWork,它也注入到其构造函数中:
public CarService(IUnitOfWork unitOfWork){
_unitOfWork = unitOfWork;
}
当在 DialogViewModel 中使用 CarService 进行查询以检索一些数据并进行一些更新时,它第一次工作正常。但是,当下次进行相同的查询以检索该数据时,它不会返回最新修改的数据,而是返回旧的/缓存的查询。使用 UnitOfWork(在 CarService 内部)的查询如下所示:
var values = _unitOfWork.GarageRepository.GetSomeValues();
_unitOfWork.GarageRepository.MakeSomeChangesToTheValuesUsingStoredProcedure();
第二次调用时,值不包含最新版本的数据;但是它已在数据库中成功更新。
我正在使用 Unity 进行 DI,这是我的容器的样子:
public class Container
{
public static UnityContainer Container = new UnityContainer();
// Called once in the AppBoostraper, as soon as the GUI application starts
public void BuildUp()
{
Container.RegisterType<IUnitOfWork, UnitOfWork>();
Container.RegisterType<ICarService, CarService>();
}
}
为什么没有返回正确的数据,我该如何解决?
我终于发现了这个问题,这与我对 unitOfWork/dbcontext 生命周期的管理有关。
我加载了一些实体,然后使用存储过程更新它们(因此代码中的实体不再是最新的),然后再次加载查询;此时,EF 从缓存而不是从数据库获取值。
我找到了两种解决此问题的方法:
-
一个相当"黑客"的,强制实体重新加载:
Context.Entry(entity).Reload();
-
使用 using 封装 unitOfWork 用法,以便在每个事务结束时释放上下文,从而在下次获取新数据。我认为这更符合UnitOfWork的用途,对我来说感觉更强大。我还将 UnitOfWork 包装在一个工厂中,所以现在它被注入到构造函数中。
using (var uOw = new unitOfWorkFactory.GetNew()) { // make the queries }
Unity 的默认 LifetimeManager 是 TransientLifetimeManager,这意味着每次解析时(包括注入时)您都会获得一个新实例。 因此,根据您的注册,您将获得一个新的CarService,每次调用Resolve()时都会有一个新的UnitOfWork实例,并在主窗口ViewModel中注入一个新的,不同的实例。
因此,您的 ViewModel 获得一个 UoW,CarService 获得一个单独的 UoW,更新一个将意味着另一个由于缓存而过时。
您需要做的是为具有适当范围的上下文设置一个 LifetimeManager,或者遵从工厂。 Unity 没有内置那么多 LM,但 LifetimeManager 类基本上是一个美化的地图(本质上有一个 Set、Get 和 Remove 方法)。
我对 WPF 及其生命周期的了解不足以建议实现。 也许它可以是单例(它将在整个程序运行时保持相同的上下文),也许它可以由线程的 CallContext 支持。
您的另一个选择是在通过调用 Container.Resolve<CarService>(new ParameterOverride("unitOfWork", _unitOfWork))
解析车载服务时传递 UoW 实例。 这将使生命周期管理与主窗口 ViewModel 的生命周期相关联。 但是,这种方法存在问题,因为您的 VM 类对 CarService 了解得太多(值得注意的是,它有一个 UoW)。