在应用程序范围内保留 DBContext 的单个实例,PRISM 和 Unity IoC
Keeping a single instance of DBContext in application scope, PRISM & Unity IoC
好的,我是 DI 和使用 IoC 容器的新手。我正在为 WPF 编写 Prism & Unity 应用程序。
我想实例化多个 DBContext 的实例,并将其传递给使用它的每个视图模型。我故意遗漏了存储库 class,因为我觉得来自 EF 的 CRUD 就足够了,而且只有我在处理这个应用程序。
我知道我可以在每个 ViewModel 中初始化 DBContext,但有时我会有多个相同 DBContext 的实例,我觉得这似乎是一种不好的做法并且会产生很大的开销。
过去几天我用谷歌搜索了这个,发现自己有点困惑。
您的指导将不胜感激。
将 IoC 中的生命周期类型设置为 Singleton 以解析 DBContext。然后每次调用 Resolve() 时,您将获得相同的 DBContext 实例。我还没有尝试过这个,但这是一个让你开始的想法。也许阅读一下 C# 中的对象生命周期。
在 Unity 中,我认为它看起来像这样:
var container = new UnityContainer();
container.RegisterType(typeof(IMyInterface),
typeof(MyImplementation),
"singletonReg",
new ContainerControlledLifetimeManager());
重写 boostrapper class 的 ConfigureContainer()
方法并调用 Container
:
的 RegisterInstance
方法
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterInstance(new YourDbContext());
}
然后您可以像往常一样解析上下文的唯一实例:
var context = _container.Resolve<YourDbContext>();
所以直接的答案是大多数(可能是所有)DI 容器支持在注册对象时指定对象生命周期的能力。通常这是通过注册单例实例或注册类型并指定它具有“应用程序”生命周期来完成的,即对象在应用程序的整个生命周期中都存在。
也就是说,您通常不希望 Entity Framework 上下文具有应用程序生命周期。
I feel as though that is a bad practice and would have significant overhead.
实际上,事实恰恰相反——EF 上下文的最佳做法是只在必要时才存在。根据 Microsoft,与构建上下文模型相关的开销应该是最小的:
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain. Model caching can be turned off by setting the CacheForContextType property on ModelBuilder to ‘false’ in the OnModelCreating method.
再次 here(强调我的):
Entity Framework’s contexts are meant to be used as short-lived instances in order to provide the most optimal performance experience. Contexts are expected to be short lived and discarded, and as such have been implemented to be very lightweight and reutilize metadata whenever possible. In web scenarios it’s important to keep this in mind and not have a context for more than the duration of a single request. Similarly, in non-web scenarios, context should be discarded based on your understanding of the different levels of caching in the Entity Framework. Generally speaking, one should avoid having a context instance throughout the life of the application, as well as contexts per thread and static contexts.
事实上,创建一个在应用程序的整个生命周期中都存在的上下文可能会出现问题,因为 object caching 这可能会导致您的上下文变得非常大:
By default when an entity is returned in the results of a query, just before EF materializes it, the ObjectContext will check if an entity with the same key has already been loaded into its ObjectStateManager. If an entity with the same keys is already present EF will include it in the results of the query. Although EF will still issue the query against the database, this behavior can bypass much of the cost of materializing the entity multiple times.
The more you use an ObjectContext, generally the bigger it gets. This is because it holds a reference to all the Entities it has ever known about, essentially whatever you have queried, added or attached. So you should reconsider sharing the same ObjectContext indefinitely
你说:
I know I can initialize the DBContext in each of the ViewModels, but then I would have multiple instances of sometimes the same DBContext.
我认为,如果您的 ViewModel 寿命很长,那么将 DBContext 的范围限定到 ViewModel 的寿命可能仍然太长(由于对象缓存)。最好的方法是识别 ViewModel 中的工作单元,并将 DBContext 的生命周期限定在这些单元内。
另一种选择是禁用对象缓存。
好的,我是 DI 和使用 IoC 容器的新手。我正在为 WPF 编写 Prism & Unity 应用程序。
我想实例化多个 DBContext 的实例,并将其传递给使用它的每个视图模型。我故意遗漏了存储库 class,因为我觉得来自 EF 的 CRUD 就足够了,而且只有我在处理这个应用程序。
我知道我可以在每个 ViewModel 中初始化 DBContext,但有时我会有多个相同 DBContext 的实例,我觉得这似乎是一种不好的做法并且会产生很大的开销。
过去几天我用谷歌搜索了这个,发现自己有点困惑。
您的指导将不胜感激。
将 IoC 中的生命周期类型设置为 Singleton 以解析 DBContext。然后每次调用 Resolve() 时,您将获得相同的 DBContext 实例。我还没有尝试过这个,但这是一个让你开始的想法。也许阅读一下 C# 中的对象生命周期。
在 Unity 中,我认为它看起来像这样:
var container = new UnityContainer();
container.RegisterType(typeof(IMyInterface),
typeof(MyImplementation),
"singletonReg",
new ContainerControlledLifetimeManager());
重写 boostrapper class 的 ConfigureContainer()
方法并调用 Container
:
RegisterInstance
方法
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterInstance(new YourDbContext());
}
然后您可以像往常一样解析上下文的唯一实例:
var context = _container.Resolve<YourDbContext>();
所以直接的答案是大多数(可能是所有)DI 容器支持在注册对象时指定对象生命周期的能力。通常这是通过注册单例实例或注册类型并指定它具有“应用程序”生命周期来完成的,即对象在应用程序的整个生命周期中都存在。
也就是说,您通常不希望 Entity Framework 上下文具有应用程序生命周期。
I feel as though that is a bad practice and would have significant overhead.
实际上,事实恰恰相反——EF 上下文的最佳做法是只在必要时才存在。根据 Microsoft,与构建上下文模型相关的开销应该是最小的:
There is some cost involved in discovering the model, processing Data Annotations and applying fluent API configuration. To avoid incurring this cost every time a derived DbContext is instantiated the model is cached during the first initialization. The cached model is then re-used each time the same derived context is constructed in the same AppDomain. Model caching can be turned off by setting the CacheForContextType property on ModelBuilder to ‘false’ in the OnModelCreating method.
再次 here(强调我的):
Entity Framework’s contexts are meant to be used as short-lived instances in order to provide the most optimal performance experience. Contexts are expected to be short lived and discarded, and as such have been implemented to be very lightweight and reutilize metadata whenever possible. In web scenarios it’s important to keep this in mind and not have a context for more than the duration of a single request. Similarly, in non-web scenarios, context should be discarded based on your understanding of the different levels of caching in the Entity Framework. Generally speaking, one should avoid having a context instance throughout the life of the application, as well as contexts per thread and static contexts.
事实上,创建一个在应用程序的整个生命周期中都存在的上下文可能会出现问题,因为 object caching 这可能会导致您的上下文变得非常大:
By default when an entity is returned in the results of a query, just before EF materializes it, the ObjectContext will check if an entity with the same key has already been loaded into its ObjectStateManager. If an entity with the same keys is already present EF will include it in the results of the query. Although EF will still issue the query against the database, this behavior can bypass much of the cost of materializing the entity multiple times.
The more you use an ObjectContext, generally the bigger it gets. This is because it holds a reference to all the Entities it has ever known about, essentially whatever you have queried, added or attached. So you should reconsider sharing the same ObjectContext indefinitely
你说:
I know I can initialize the DBContext in each of the ViewModels, but then I would have multiple instances of sometimes the same DBContext.
我认为,如果您的 ViewModel 寿命很长,那么将 DBContext 的范围限定到 ViewModel 的寿命可能仍然太长(由于对象缓存)。最好的方法是识别 ViewModel 中的工作单元,并将 DBContext 的生命周期限定在这些单元内。
另一种选择是禁用对象缓存。