75

什么时候应该调用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;
    }
    
4

6 回答 6

115

实际上这是两个问题合二为一:

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

答案:

  1. 从不 1using是一个隐含Dispose()在一个try-finally块中。Dispose当异常发生较早时,可能会遗漏单独的语句。此外,在最常见的情况下,根本不调用Dispose(隐式或显式)是无害的。

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


1正如一些人所评论的,当上下文是实现IDisposable自身并共享其生命周期的组件的一部分时,此规则的例外情况。在这种情况下,您将调用组件context.Dispose()Dispose方法。

于 2013-03-27T18:52:01.683 回答
40

我遵循了一些很好的教程来使用 EF,它们没有处理上下文。

我对此有点好奇,我注意到即使是备受尊敬的 Microsoft VIP 也不会处理上下文。我发现您不必在正常情况下处理 dbContext 。

如果您想了解更多信息,可以阅读这篇总结了原因的博客文章。

于 2014-06-21T15:09:31.200 回答
16

更好的是:

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

无需从作用域外返回结果using;只需立即返回它,您仍然可以获得所需的处置行为。

于 2015-04-16T20:03:31.650 回答
2

您可以将数据库上下文定义为类字段,并实现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;
    }
}
于 2016-12-05T21:39:00.527 回答
1

正如丹尼尔所提到的,您不必处理 dbContext。

文章

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

所以:

public static string GetName(string userId) =>
    new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);
于 2019-10-15T15:34:01.310 回答
1

在某些情况下,可能需要处理上下文。

在 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;
            }
        }
    }
于 2020-08-11T11:39:57.853 回答