DbContext全局作用域vs方法级作用域
本文关键字:作用域 方法 vs DbContext 全局 | 更新日期: 2023-09-27 18:02:20
如果有一个类作为数据访问层,并为实体提供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
但这完全取决于你的需求和你正在构建的是哪种服务。