C# 实体框架上下文应该放在Using语句中吗?
实体框架上下文对象实现了一个Dispose()方法,该方法“释放对象上下文使用的资源”。它真正的作用是什么?总是把它放到using{}语句中会是一件坏事吗?我见过它在使用和不使用using语句的情况下都被使用 我特别打算在WCF服务方法中使用EF上下文,创建上下文,执行一些linq并返回答案C# 实体框架上下文应该放在Using语句中吗?,c#,entity-framework,C#,Entity Framework,实体框架上下文对象实现了一个Dispose()方法,该方法“释放对象上下文使用的资源”。它真正的作用是什么?总是把它放到using{}语句中会是一件坏事吗?我见过它在使用和不使用using语句的情况下都被使用 我特别打算在WCF服务方法中使用EF上下文,创建上下文,执行一些linq并返回答案 编辑:我似乎不是唯一一个对此感到疑惑的人。另一个问题是Dispose()方法中到底发生了什么。有些人说它会关闭连接,有些文章则说不会。这是怎么回事?通常,如果您实例化了一个实现IDisposable的类,那
编辑:我似乎不是唯一一个对此感到疑惑的人。另一个问题是Dispose()方法中到底发生了什么。有些人说它会关闭连接,有些文章则说不会。这是怎么回事?通常,如果您实例化了一个实现IDisposable的类,那么您有责任对其调用Dispose。在除一种情况外的所有情况下,这意味着一个using块。由于您不知道垃圾收集器何时处理一个项,所以如果您知道何时处理完,则最好将实现IDisposable的对象包装在using块中。如果您创建了一个上下文,则必须稍后处理它。是否应该使用
using
语句取决于上下文的生存时间
using
语句,因为它提供了异常处理,而无需任何其他代码using
语句,必须自己调用Dispose()
并注意始终调用它Dispose()
对对象上下文有什么作用
我没有查看代码,但至少我检查了它以关闭数据库与其底层套接字的连接或传输机制使用的任何资源。当您处置时,ObjectContext处置其他拥有的对象 包括像EntityConnection这样的东西,它包装了实际的数据库连接,即通常是SqlConnection 因此,“如果”SqlConnection处于打开状态,则当您处理ObjectContext时,它将被关闭。Per:“您可以显式地处理ObjectContext,或者等待垃圾回收器执行该作业。”
因此,简而言之,虽然不需要using语句,但如果您知道已经使用完ObjectContext,那么这是最佳做法,因为资源会立即释放,而不是等待垃圾回收 我已经注意到(尽管只有一个应用程序)显式处理导致了mscorlib中的线程中止异常,这些异常在应用程序代码之前被捕获,但至少在我的情况下导致了明显的性能下降。没有对这个问题做过任何有意义的研究,但是如果你这样做的话,可能有一些值得考虑的事情。只需观察调试输出,看看是否得到相同的结果 如果Dispose关闭了与DB的连接,那么调用它是个坏主意。
例如,在ADO.NET中,连接位于连接池中,并且在超时或应用程序池停止之前永远不会关闭连接。我确实对ADO.NET和EF v.6以及SQL表中监视的连接进行了测试
select * from sys.dm_exec_connections
要测试的方法如下所示:
1) 使用ADO.net
using(var Connection = new SqlConnection(conString))
{
using (var command = new SqlCommand(queryString, Connection))
{
Connection.Open();
command.ExecuteNonQueryReader();
throw new Exception() // Connections were closed after unit-test had been
//finished. Expected behaviour
}
}
2) net与我们的使用
var Connection = new SqlConnection(conString);
using (var command = new SqlCommand(queryString, Connection))
{
Connection.Open();
command.ExecuteNonQueryReader();
throw new Exception() // Connections were NOT closed after unit-test had been finished
finished. I closed them manually via SQL. Expected behaviour
}
1) 使用EF
using (var ctx = new TestDBContext())
{
ctx.Items.Add(item);
ctx.SaveChanges();
throw new Exception() // Connections were closed, as expected.
}
2) EF不使用
var ctx = new TestDBContext();
ctx.Items.Add(item);
ctx.SaveChanges();
throw new Exception() // Connections WERE successfully closed, as NOT expected.
我不知道为什么会这样,但EF会自动关闭连接。而且,所有使用EF的存储库和UnitOfWork模式都不使用using。这对我来说很奇怪,因为DBContext是一次性类型,但这是事实
也许在微软他们做了一些新的处理?EF5和之前的版本
using { ...
// connecction open here.
...
context.Blogs.Add(blog);
context.SaveChanges(); // query etc now opens and immediately closes
...
context.Blogs.Add(blog);
context.SaveChanges(); // query etc now opens and immediately closes
}
EF6及以后版本
using {
// connecction open here.
...
context.Blogs.Add(blog);
context.SaveChanges();
// The underlying store connection remains open for the next operation
...
context.Blogs.Add(blog);
context.SaveChanges();
// The underlying store connection is still open
} // The context is disposed – so now the underlying store connection is closed
Reference:True,但问题是Dispose()方法对EF上下文的作用。从我在这个话题上的发现来看,这似乎并不那么重要!谢谢你问这个问题。因此,我发现我担心在应用程序中忘记的所有Dispose调用可能不像我所担心的那样重要(通过阅读),我假设EF还跟踪对象更改,这在这两种情况下可能都是较大的资源。我只是快速查看了DataContext类,引用的文章似乎完全错误-DataContext.Dispose()尝试关闭基础连接。(可能是我错了,连接通常是关闭的,但至少它尝试关闭它。我无法想象LINQ to SQL会因为性能影响而为每个请求创建一个新的连接,所以我倾向于相信连接会在数据上下文处于活动状态时打开。)@Johan:不管它今天做什么。这不是你的密码。明天可能会改变。鉴于您依赖于今天的实现,它可能明天就会改变,只是为了教您为什么不改变!GC被要求不明确地处理事物。必须(如果可能)处置引用非托管资源的对象。所以这里真正的问题是——EF上下文引用非托管资源吗?如果不是,那么你不应该处理它…这是错误的或误导性的。您引用的文章是关于管理连接的,是关于手动调用
connection.Open()
(您不会将其转换为示例代码),而不是关于Dispose()
。如果您不手动调用connection.Open()
(将其留给EF connection management),则您的//基础存储连接仍处于打开状态。与OP问题无关。实际上很简单:如果您不手动打开连接(如ctx.Database.connection.open();
),EF6会处理好它,并管理每个查询的打开/关闭(请参阅ADO连接池,为什么这不是一个坏主意)。但是如果你手动打开它,EF6会考虑你知道你在做什么,并让它打开。