实体框架和上下文配置

时间:2013-03-27 18:38:28

标签: entity-framework dbcontext idisposable

何时应该使用实体框架调用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;
    }
    

6 个答案:

答案 0 :(得分:93)

事实上,这是两个问题:

  1. 我应该何时使用上下文的Dispose()
  2. 我的背景的生命周期应该是什么?
  3. 数目:

    1. 从不 1 usingDispose()块中的隐式try-finally。当先前发生异常时,可能会错过单独的Dispose语句。此外,在大多数情况下,根本不调用Dispose(隐式或明确地)isn't harmful

    2. 参见例如Entity Framework 4 - lifespan/scope of context in a winform application。简而言之:生命周期应该“短”,静态环境不好。


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