我已经阅读了很多文章,解释如何设置实体框架的DbContext,以便使用各种DI框架只创建和使用每个HTTP web请求。
为什么一开始这是个好主意?使用这种方法有什么好处?在某些情况下,这是个好主意吗?在每个存储库方法调用实例化dbcontext时,是否有一些事情是使用这种技术可以做而不能做的?
我已经阅读了很多文章,解释如何设置实体框架的DbContext,以便使用各种DI框架只创建和使用每个HTTP web请求。
为什么一开始这是个好主意?使用这种方法有什么好处?在某些情况下,这是个好主意吗?在每个存储库方法调用实例化dbcontext时,是否有一些事情是使用这种技术可以做而不能做的?
当前回答
Another understated reason for not using a singleton DbContext, even in a single threaded single user application, is because of the identity map pattern it uses. It means that every time you retrieve data using query or by id, it will keep the retrieved entity instances in cache. The next time you retrieve the same entity, it will give you the cached instance of the entity, if available, with any modifications you have done in the same session. This is necessary so the SaveChanges method does not end up with multiple different entity instances of the same database record(s); otherwise, the context would have to somehow merge the data from all those entity instances.
这是一个问题,因为单例DbContext会成为一个定时炸弹,最终会缓存整个数据库和。net对象在内存中的开销。
只有通过使用. notracking()扩展方法来使用Linq查询,才能避免这种行为。而且现在的电脑有很多内存。但这通常不是理想的行为。
其他回答
在这个问题或讨论中没有真正解决的一件事是DbContext不能取消更改的事实。您可以提交更改,但不能清除更改树,因此如果您使用了每个请求上下文,那么无论出于何种原因需要丢弃更改,都是不走运的。
Personally I create instances of DbContext when needed - usually attached to business components that have the ability to recreate the context if required. That way I have control over the process, rather than having a single instance forced onto me. I also don't have to create the DbContext at each controller startup regardless of whether it actually gets used. Then if I still want to have per request instances I can create them in the CTOR (via DI or manually) or create them as needed in each controller method. Personally I usually take the latter approach as to avoid creating DbContext instances when they are not actually needed.
这也取决于你从哪个角度看问题。对我来说,每个请求实例从来没有意义。DbContext真的属于Http Request吗?就行为而言,这是错误的地方。您的业务组件应该创建上下文,而不是Http请求。然后,您可以根据需要创建或丢弃业务组件,而不必担心上下文的生命周期。
实体框架需要特别注意的另一个问题是,当组合使用创建新实体、延迟加载,然后使用这些新实体时(从相同的上下文中)。如果你不使用IDbSet。创建(vs只是新建),当它从创建它的上下文检索时,对该实体的惰性加载将不起作用。例子:
public class Foo {
public string Id {get; set; }
public string BarId {get; set; }
// lazy loaded relationship to bar
public virtual Bar Bar { get; set;}
}
var foo = new Foo {
Id = "foo id"
BarId = "some existing bar id"
};
dbContext.Set<Foo>().Add(foo);
dbContext.SaveChanges();
// some other code, using the same context
var foo = dbContext.Set<Foo>().Find("foo id");
var barProp = foo.Bar.SomeBarProp; // fails with null reference even though we have BarId set.
我喜欢它的地方在于,它将工作单元(正如用户看到的那样——即页面提交)与ORM意义上的工作单元对齐。
因此,您可以使整个页面提交都是事务性的,如果您公开CRUD方法,并且每个方法都创建一个新的上下文,则无法做到这一点。
我同意之前的观点。可以说,如果你打算在单线程应用中共享DbContext,你将需要更多的内存。例如,我在Azure上的web应用程序(一个额外的小实例)需要另外150mb的内存,而我每小时大约有30个用户。
这是一个真实的例子:应用程序已经在中午12点部署
Another understated reason for not using a singleton DbContext, even in a single threaded single user application, is because of the identity map pattern it uses. It means that every time you retrieve data using query or by id, it will keep the retrieved entity instances in cache. The next time you retrieve the same entity, it will give you the cached instance of the entity, if available, with any modifications you have done in the same session. This is necessary so the SaveChanges method does not end up with multiple different entity instances of the same database record(s); otherwise, the context would have to somehow merge the data from all those entity instances.
这是一个问题,因为单例DbContext会成为一个定时炸弹,最终会缓存整个数据库和。net对象在内存中的开销。
只有通过使用. notracking()扩展方法来使用Linq查询,才能避免这种行为。而且现在的电脑有很多内存。但这通常不是理想的行为。