DbContext全局作用域vs方法级作用域



如果有一个类作为数据访问层,并为实体提供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:

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)

甚至还有第三种基于手动或自动依赖注入的方法:

public interface ISomeService 
{
     // Interface members
}
public class SomeService : ISomeService
{
    public SomeService(DbContext dbContext)
    {
         DbContext = dbContext;
    }
    private DbContext DbContext { get; }
}

那么,SomeService将不负责定义注入的 DbContext的生命周期,而是由外部类来定义

这样,你的服务就专注于做应该做的事情(处理域和读/写数据)。

根据不同的执行环境,你会想要不同的DbContext生活方式:每个服务实例,每个请求,每个线程…根据具体情况,这里有很多选择。

也许你没有考虑另一个场景:两个或多个服务之间的共享事务。您需要将实例化DbContext的责任转移到上层,然后您将在所有参与的服务上注入相同的DbContext,然后您将全局确认或放弃整个事务。

EF的性能是由几个因素组成的,DbContext的范围是其中之一。

关于作用域的一些背景信息可以在这里找到:https://msdn.microsoft.com/en-us/data/jj729737.aspx

Scope不仅与性能有关,还与返回的对象有关。如果应用了延迟加载,并且在访问某些导航属性之前处理了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;}
}

因此,您可以使用投影来限制返回的数据集,而不是返回整个对象。您可以使用它来减少数据库服务器上的负载,因为查询将不那么冗长,但它也有助于在处理上下文之前加载所有所需的数据。有关生成查询的一些示例,请参阅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

但这完全取决于你的需求和你正在构建的是哪种服务。

最新更新