实体框架并调用 context.dispose()

问题描述 投票:0回答:6

什么时候应该使用实体框架调用

DbContext.dispose()

  1. 这个想象的方法不好吗?

    public static string GetName(string userId)
    {
        var context = new DomainDbContext();
        var userName = context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
        context.Dispose();
        return userName;
    }
    
  2. 这样更好吗?

    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;
    }
    
  3. 这样更好吗?也就是说,在使用 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;
    }
    
entity-framework dbcontext idisposable
6个回答
123
投票

事实上这是两个问题合而为一:

  1. 我什么时候应该
    Dispose()
    上下文?
  2. 我的上下文的生命周期应该是多长?

答案:

  1. 从不1

    using
    Dispose()
    块中的隐式
    try-finally
    。当异常较早发生时,可能会错过单独的
    Dispose
    语句。此外,在大多数常见情况下,根本不调用
    Dispose
    (无论是隐式还是显式)并没有什么害处

  2. 参见例如Entity Framework 4 - winform 应用程序中上下文的生命周期/范围。简而言之:生命周期应该“短”,静态上下文不好。


1 正如一些人评论的那样,此规则的一个例外是当上下文是实现

IDisposable
本身并共享其生命周期的组件的一部分时。在这种情况下,您可以在组件的
context.Dispose()
方法中调用
Dispose


42
投票

下面有新答案。上一篇目前已过时。

重要更新: 看起来当前的建议是处置 DbContext(我同意)但是如果您通过依赖项注入创建它,Asp.net Core 将在请求结束时为您执行此操作。

所以,如果你这样做

public class MyController
{
    private readonly ApplicationDbContext _context;

    public MyController(ApplicationDbContext context)
    {
        _context = context;
    }
}

Asp.net Core 为您配置 DbContext。 更多信息请点击这里。

最终结果是为每个应用创建一个ApplicationDbContext实例 请求并传递给控制器以执行工作单元之前 请求结束时被处理。


17
投票

更好:

public static string GetName(string userId)
{
    using (var context = new DomainDbContext()) {
        return context.UserNameItems.FirstOrDefault(x => x.UserId == userId);
    }
}

无需从

using
范围之外返回结果;只需立即归还它,您仍然会得到所需的处置行为。


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;
    }
}

2
投票

在某些情况下,人们可能想要处理上下文。

就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;
            }
        }
    }

0
投票

正如 Daniel 提到的,您不必处置 dbContext。

摘自文章

尽管它确实实现了 IDisposable,但它只是实现了它,因此您可以在某些特殊情况下调用 Dispose 作为保护措施。默认情况下,DbContext 会自动为您管理连接。

所以:

public static string GetName(string userId) =>
    new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);
© www.soinside.com 2019 - 2024. All rights reserved.