此答案与在 ASP.NET 视图中使用已加载实体的问题中提到的问题特别相关。该问题询问如何在没有using 块或处置DbContext 的情况下解决此问题,但是我建议这样做。
原因是通常不希望在 ASP.NET 视图中使用实体框架对象,因为这些对象不仅仅是普通的 POCO 对象;它们隐藏了允许它们充当底层数据库代理的逻辑,因此它们对创建它们的DbContext 的状态具有隐藏的依赖关系。
这是一个人为的示例,使用 Employee 和 Department 的 EF 模型和 DbContext:
public class CompanyDbContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
public class Department
{
public long Id { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public long Id { get; set; }
public long DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
如果在 ASP.NET 应用程序中使用这些,我将创建一些不绑定到实体框架的单独模型,供 ASP.NET 使用。例如:
public class DepartmentModel
{
public long Id { get; set; }
public List<EmployeeModel> Employees { get; set; }
}
public class EmployeeModel
{
public long Id { get; set; }
public long DepartmentId { get; set; }
}
一些注意事项:
根据 MSDN 文档,“A DbContext 表示 UnitOfWork 和 Repository 模式的组合” - https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view=entity-framework-6.2.0 - 因此,DbContext 应该是短暂的尽可能。
从上下文加载数据时,可以使用DbSet<>.Include() - https://docs.microsoft.com/en-us/ef/ef6/querying/related-data检索相关实体
一般来说,将“数据”层与“视图”层解耦是有意义的——出于各种原因,其中一些在此处列出:https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5——这涉及到EF 对象和 POCO 模型。
用于查询DbContext 的逻辑将使用 EF 查询数据,并使用 POCO 模型返回该数据,这样只有直接处理DbContext 的逻辑才与 EF 对象有任何关系。例如:
public List<DepartmentModel> GetAllDepartments()
{
using (var ctx = new CompanyDbContext())
{
// Ensure that related data is loaded
var departments = ctx.Departments
.Include(d => d.Employees);
// Manual mapping by converting into a new set of models to be used by the Views
var models = departments
.Select(d => new DepartmentModel
{
Id = d.Id,
Employees = d.Employees
.Select(e => new EmployeeModel
{
Id = e.Id,
DepartmentId = e.DepartmentId
})
.ToList(),
})
.ToList();
return models;
}
}
能够使用这些 POCO 模型,同时需要一些额外的样板代码,提供了 DbContext 和 ASP.NET 之间的完全分离,允许使用数据而无需 ASP.NET 视图/控制器与生命周期或DbContext 的状态。
有时这可能看起来好像这种方法违反了“DRY”原则,但是我要指出,EF 对象和 ViewModel 对象的存在是为了解决不同的问题,并且 ViewModel 对象采用不同的形状并不少见,或者甚至需要不适合添加到 EF 类的其他字段/属性。
最后,上面使用“手动”映射,但如果映射非常简单明了,那么使用 AutoMapper 会更有意义:Cleanest Way To Map Entity To DTO With Linq Select?