什么时候应该使用实体框架调用
DbContext.dispose()
?
这个想象的方法不好吗?
public static string GetName(string userId)
{
var context = new DomainDbContext();
var userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
context.Dispose();
return userName;
}
这样更好吗?
public static string GetName(string userId)
{
string userName;
using(var context = new DomainDbContext()) {
userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
context.Dispose();
}
return userName;
}
这样更好吗?也就是说,在使用 using() 时不应该调用 context.Dispose() 吗?
public static string GetName(string userId)
{
string userName;
using(var context = new DomainDbContext()) {
userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
}
return userName;
}
事实上这是两个问题合而为一:
Dispose()
上下文?答案:
从不1。
using
是 Dispose()
块中的隐式 try-finally
。当异常较早发生时,可能会错过单独的 Dispose
语句。此外,在大多数常见情况下,根本不调用 Dispose
(无论是隐式还是显式)并没有什么害处。参见例如Entity Framework 4 - winform 应用程序中上下文的生命周期/范围。简而言之:生命周期应该“短”,静态上下文不好。
1 正如一些人评论的那样,此规则的一个例外是当上下文是实现
IDisposable
本身并共享其生命周期的组件的一部分时。在这种情况下,您可以在组件的 context.Dispose()
方法中调用 Dispose
。
下面有新答案。上一篇目前已过时。
重要更新: 看起来当前的建议是处置 DbContext(我同意)但是如果您通过依赖项注入创建它,Asp.net Core 将在请求结束时为您执行此操作。
所以,如果你这样做
public class MyController
{
private readonly ApplicationDbContext _context;
public MyController(ApplicationDbContext context)
{
_context = context;
}
}
Asp.net Core 为您配置 DbContext。 更多信息请点击这里。
最终结果是为每个应用创建一个ApplicationDbContext实例 请求并传递给控制器以执行工作单元之前 请求结束时被处理。
更好:
public static string GetName(string userId)
{
using (var context = new DomainDbContext()) {
return context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
}
}
无需从
using
范围之外返回结果;只需立即归还它,您仍然会得到所需的处置行为。
您可以将数据库上下文定义为类字段,并实现
IDisposable
。如下所示:
public class MyCoolDBManager : IDisposable
{
// Define the context here.
private DomainDbContext _db;
// Constructor.
public MyCoolDBManager()
{
// Create a new instance of the context.
_db = new DomainDbContext();
}
// Your method.
public string GetName(string userId)
{
string userName = _db.UserNameItems.FirstOrDefault(x => x.UserId == userId);
return userName;
}
// Implement dispose method.
// NOTE: It is better to follow the Dispose pattern.
public void Dispose()
{
_db.dispose();
_db = null;
}
}
在某些情况下,人们可能想要处理上下文。
就OP示例的简单而言,
using
关键字就足够了。
那么我们什么时候需要使用
dispose
?
看看这个场景:您需要处理一个大文件或通信或 Web 服务合同,这将生成数百或数千条 BD 记录。
在 EF 中添加 (+400) 数千或数百个实体对性能来说是一种痛苦:实体框架性能问题,saveChanges 非常慢
该网站对该解决方案进行了很好的描述:https://entityframework.net/improve-ef-add-performance
TL;DR - 我实现了这个,所以我最终得到了这样的结果:
/// <summary>
/// Convert some object contract to DB records
/// </summary>
/// <param name="objs"></param>
public void SaveMyList(WCF.MyContract[] objs)
{
if (objs != null && objs.Any())
{
try
{
var context = new DomainDbContext();
try
{
int count = 0;
foreach (var obj in objs)
{
count++;
// Create\Populate your object here....
UserNameItems myEntity = new UserNameItems();
///bla bla bla
context.UserNameItems.Add(myEntity);
// https://entityframework.net/improve-ef-add-performance
if (count % 400 == 0)
{
context.SaveChanges();
context.Dispose();
System.Threading.Thread.Sleep(0); // let the system breathe, other processes might be waiting, this one is a big one, so dont use up 1 core for too long like a scumbag :D
context = new DomainDbContext();
}
}
context.SaveChanges();
}
finally
{
context.Dispose();
context = null;
}
Log.Info("End");
}
catch (Exception ex)
{
Log.Error(string.Format("{0}-{1}", "Ups! something went wrong :( ", ex.InnerException != null ? ex.InnerException.ToString() : ex.Message), ex);
throw ex;
}
}
}
正如 Daniel 提到的,您不必处置 dbContext。
摘自文章:
尽管它确实实现了 IDisposable,但它只是实现了它,因此您可以在某些特殊情况下调用 Dispose 作为保护措施。默认情况下,DbContext 会自动为您管理连接。
所以:
public static string GetName(string userId) =>
new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);