何时应该使用实体框架调用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;
}
答案 0 :(得分:93)
事实上,这是两个问题:
Dispose()
?数目:
从不 1 。 using
是Dispose()
块中的隐式try-finally
。当先前发生异常时,可能会错过单独的Dispose
语句。此外,在大多数情况下,根本不调用Dispose
(隐式或明确地)isn't harmful。
参见例如Entity Framework 4 - lifespan/scope of context in a winform application。简而言之:生命周期应该“短”,静态环境不好。
1 正如有些人评论的那样,这个规则的一个例外是当一个上下文是一个实现IDisposable
本身并分享其生命周期的组件的一部分时。在这种情况下,您可以在组件的context.Dispose()
方法中调用Dispose
。
答案 1 :(得分:34)
我遵循了一些很好的教程来使用EF,他们不会处理上下文。
我对此有点好奇,我注意到即使是备受尊敬的微软VIP也不会处理上下文。我发现你不必在正常情况下处理dbContext 。
如果您想了解更多信息,可以阅读总结原因的this blog post。
答案 2 :(得分:12)
更好:
public static string GetName(string userId)
{
using (var context = new DomainDbContext()) {
return context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
}
}
无需从using
范围之外返回结果;只需立即归还,您仍然可以获得理想的处置行为。
答案 3 :(得分:3)
您可以将数据库上下文定义为类字段,并实现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;
}
}
答案 4 :(得分:1)
如Daniel所述,您不必处置dbContext。
来自article:
即使它确实实现了IDisposable,也仅实现了它,因此在某些特殊情况下,您可以将Dispose称为安全措施。默认情况下,DbContext自动为您管理连接。
所以:
public static string GetName(string userId) =>
new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);
答案 5 :(得分:0)
在某些情况下,可能需要处理上下文。
在OP示例的简单术语上,using
关键字就足够了。
那么我们什么时候需要使用dispose
?
看看这种情况:您需要处理一个大文件,通信或Web服务合同,这将生成数百或数千个BD记录。
在EF中添加(+400)数千或数百个实体是性能上的难题:Entity framework performance issue, saveChanges is very slow
此网站上对解决方案的描述非常好: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;
}
}
}