DbContext全局范围与方法级别范围

时间:2016-08-13 12:06:55

标签: c# entity-framework entity-framework-6

如果有一个类作为数据访问层,并为实体提供CRUD操作的功能,那么在考虑性能时,哪个版本是最佳实践。多线程环境(即此类的方法由多个线程同时调用。)。 。

版本1:

在类级别创建的DbContext,由所有方法共享。 。

    class EmployeeService{

     private DbContext db=new DbContext();

     public  Employee GetEmployee(int id)

         return db.Employees.Find(id);
     }


     public void AddEmployee(Employee employee){

         db.Employees.Add(employee);
         db.SaveChanges();
     }
}

版本2:

每个方法调用的DbContext。

class EmployeeService{

     public  Employee GetEmployee(int id){
        using(DbContext db=new DbContext()){
         return db.Employees.Find(id);
        }
     }


     public void AddEmployee(Employee employee){         
        using(DbContext db=new DbContext()){                 
            db.Employees.Add(employee);
           db.SaveChanges();    
        }
     }
}

更新 可能是发布的问题在范围上过于通用,导致需要考虑几点。

感兴趣的是,实例化DbContext对象的成本。可以根据请求创建(版本2)还是重量级的对象,更好地创建几个实例并在不同的实例之间共享它们电话(版本1)

2 个答案:

答案 0 :(得分:2)

甚至还有第三种方法基于手动或自动dependency injection

public interface ISomeService 
{
     // Interface members
}

public class SomeService : ISomeService
{
    public SomeService(DbContext dbContext)
    {
         DbContext = dbContext;
    }

    private DbContext DbContext { get; }
}

然后,SomeService不负责定义注入 DbContext的生命周期,但它是一个外部类它

这样,您的服务专注于做什么(使用域和读/写数据)。

根据执行环境的不同,您需要不同的DbContext生活方式:每个服务实例,每个请求,每个线程......这里有很多选择,具体取决于情况下。

也许您并未考虑其他方案:两个或多个服务之间的共享事务。您需要将实例化DbContext的职责转移到上层,然后您将在所有参与服务上注入相同的DbContext,并且您将在全球范围内确认或放弃整个交易。

答案 1 :(得分:1)

EF的表现由几个因素组成,DbContext的范围就是其中之一。

有关范围的一些背景信息,请访问:https://msdn.microsoft.com/en-us/data/jj729737.aspx

范围不仅与性能有关,还与返回的对象有关。如果在访问某些导航属性之前应用了延迟加载并且DbContext已被释放,则会给出异常。见http://www.entityframeworktutorial.net/EntityFramework4.3/lazy-loading-with-dbcontext.aspx

您可以编写如下代码:

public class EmployeeService
{
    public EmployeeDto GetEmployee(int id)
    {
        using(DbContext db=new DbContext())
        {
            return db.Employees.Select(e =>
                new EmployeeDto
                {
                    Id = e.Id,
                    Name = e.Name,
                    Department = e.Department.Name
                }).First(e => e.Id == id);
        }
    }
}

public class EmployeeDto
{
    public int Id { get;set;}
    public string Name { get;set;}
    public string Department { get;set;}
}

因此,您可以使用projection来限制返回的数据集,而不是返回整个对象。这可以用来减少数据库服务器上的负载,因为查询将更简洁,但它也有助于在处置上下文之前加载所有必需的数据。有关生成的查询的一些示例,请参阅http://www.entityframeworktutorial.net/querying-entity-graph-in-entity-framework.aspx

所以我的建议是限制DbContext的范围。你可以注入DbContext但是你无法控制DbContext它会导致这样的错误:http://wallacekelly.blogspot.nl/2012/01/linq-to-entities-objectdisposedexceptio.html

但这完全取决于您的需求以及您正在建设的服务类型。