有没有正确的方法来使用db上下文类?

时间:2014-01-12 13:02:37

标签: c# entity-framework dbcontext

我想知道在使用网站的上下文类连接到db时,性能和一般最佳做法的差异是什么。 考虑这两种不同的方法时,最好的方法是什么:

public class Repository()
{
    Private Context context;

    public List<User> GetUsers()
    {
        return this.context.Users.ToList();
    }

public class Repository()
{        
    public List<User> GetUsers()
    {
        using (Context context = new context())
        {
            return context.Users.ToList(); 
        }
    }
 }

如果将结果作为ListIEnumerable返回,是否重要?

4 个答案:

答案 0 :(得分:5)

MSDN

复制

寿命

上下文的生命周期在创建实例时开始,在实例处理或垃圾收集时结束。如果您希望将上下文控制的所有资源放置在块的末尾,请使用。使用时,编译器会自动创建一个try / finally块,并在finally块中调用dispose。

using (var context = new ProductContext())
{    
    // Perform data access using the context
}

在决定上下文的生命周期时,以下是一些一般性指导原则:

使用长时间运行的上下文时,请考虑以下事项: 当您将更多对象及其引用加载到内存中时,上下文的内存消耗可能会迅速增加。这可能会导致性能问题。 请记住在不再需要时处理上下文。 如果异常导致上下文处于不可恢复状态,则整个应用程序可能会终止。 随着查询和更新数据的时间之间的差距的增大,遇到并发相关问题的可能性也会增加。 使用Web应用程序时,请按请求使用上下文实例。 使用Windows Presentation Foundation(WPF)或Windows窗体时,请为每个窗体使用上下文实例。这使您可以使用上下文提供的更改跟踪功能。

答案 1 :(得分:3)

虽然你已经接受了一个(完全可以接受的)解决生命问题的答案,但我认为最重要的方面只是在克里斯的答案中被撇去。 (IMHO)它应该是选项1的最重要原因是可组合性。 (但一个重要的假设是,在选项1中,存储库在其构造函数中接收上下文,因此在一个用例中可以由多个存储库共享此上下文。)

假设您想在一个查询中加入两个实体:

from u in repo1.GetUsers()
join r in repo2.GetRoles() on u.UserId equals r.UserId
where u.UserId = ...

使用选项2,这将对用户和角色执行单独的查询,因为来自不同上下文的两个DbSet只能在内存中组合。使用选项1(和一些修改),这将使用SQL连接触发一个组合查询。

您还需要做的事情是返回IQueryable而不是List,即返回context.Users

此外,使用选项2,如果您对来自不同存储库的实体进行更改,则在一个事务中提交它们会更加精细。 (您需要在每个上下文中调用SaveChanges()个调用,包含在TransactionScope)中。

有点偏离主题,但过于相关而忽略的事实是修改后的选项1可能会让你在DbSet和你的应用程序代码之间留下一个非常非常薄的中间人。您可能会认为此存储库层没有添加任何有用的内容并完全抛弃它。

答案 2 :(得分:1)

绝对是第二种方法。
构建DbContext几乎是一种无操作。昂贵的事情是创建(而不是建立)与Db的连接,由于连接池,这只发生一次。另一方面,保持连接打开较长时间是一个坏主意(除此之外,它是非常耗费资源的)并且可能导致各种其他问题(例如,由于网络错误导致的连接中断)。

答案 3 :(得分:0)

使用第一个版本。如果需要在存储库中调用多个方法,则只需初始化一次上下文,而不是在每个方法中反复初始化它。此外,通过使用支持字段,您还可以选择利用依赖注入,这是一个强大的概念,可以使您的应用程序分离,灵活,可测试和可维护:

http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-dependency-injection