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


69

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

21
应该在使用using()时不调用context.Dispose()始终为true。这是多余的。
Gert Arnold

感谢您的评论。所以context.Dispose()仅是多余的,将其删除不会有任何效果?
辛德雷

4
using是隐式的Dispose()
Gert Arnold

和的DbContext被制成短版活-这样做无论是工作的一个“批” -并获得与它做
NSGaga,大多是不活动

您的代码中有一个错误:-)-UserNameItems当然是一个复杂的类型集合,而不是System.String集合,否则您将不会调用x.UserId。我认为您在Where后面缺少.Select(x => x.UserId)调用,或者没有对String的隐式强制转换运算符。
USR-本地ΕΨΗΕΛΩΝ

Answers:


105

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

  1. 我应该何时Dispose()上下文?
  2. 我的背景寿命应该是什么?

答案:

  1. 永远不会 1using是隐Dispose()在一个try-finally块中。Dispose较早发生异常时,可能会丢失单独的语句。此外,在最常见的情况下,不是要求Dispose所有(隐或显式)是不会对人体有害

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


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


3
嗯,如果您不使用“ using”语句来包装上下文(请参考情况1),“ Never”是否仍然适用?
gitsitgo 2013年

1
我没有完全得到尝试最后的评论,您是说尝试抓住吗?因为我添加到了catch部分,以防发生异常。您能确定在捕获异常时是否可以处置?谢谢。
埃米尔(Emil)

@batmaci不,我的意思是使用 using结构,而不是最后尝试,因为它或多或少是相同的。通过a,using您无需致电Dispose
格特·阿诺德

永不致电的答案dispose上下文是错误的-它取决于应用程序的类型-即。在MVC你重写了dispose控制器和呼叫的方法dispose上下文-你只使用时不需要手动调用它using
卢克牛逼奥布莱恩

我还是不明白。如果在使用中抛出异常。它会自动退出连接,但是连接会发生什么情况?使用中的异常是否仍会立即配置连接而不必配置在catch中?
马克·罗素

38

我遵循了一些使用EF的优秀教程,但它们并未处理上下文。

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

如果您需要更多信息,可以阅读此博客文章,总结原因。


我想指出的是,此评论来自2014年。我正在2020年撰写此评论,对于较新的EF版本或EF Core,此答案可能是完全错误的。遵循IDispose模式不应该是可选的,因为不这样做可能会引入各种问题。链接的帖子仅考虑数据库连接,但是Dispose方法的作用远不止于关闭连接。
吉列尔莫·普兰迪

16

更好的是:

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

无需从using范围外返回结果;只需立即将其退还,您仍然会获得所需的处置行为。


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

1
您可能想看看处理方式
杰里·约瑟夫

1

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

文章

即使它确实实现了IDisposable,它也仅实现了它,因此在某些特殊情况下,可以将Dispose称为安全措施。默认情况下,DbContext自动为您管理连接。

所以:

public static string GetName(string userId) =>
    new DomainDbContext().UserNameItems.FirstOrDefault(x => x.UserId == userId);

0

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

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

1
更好的模式是按objs400个块进行处理,每个块在一条using语句中有一个上下文,并有一个SaveChanges()调用。更清晰的代码(无计数,无if,等等)。无需强制调用context.Dispose。
Gert Arnold
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.