【发布时间】:2016-11-22 23:48:08
【问题描述】:
我目前正在使用 Entity Framework Core 处理 ASP .NET Core 1.0。我对数据库中的数据进行了一些复杂的计算,我不确定如何使用依赖注入构建适当的架构构建贫血域模型 (http://www.martinfowler.com/bliki/AnemicDomainModel.html)
(简体)示例:
我有以下实体:
public class Project {
public int Id {get;set;}
public string Name {get;set;}
}
public class TimeEntry
{
public int Id {get;set;}
public DateTime Date {get;set;}
public int DurationMinutes {get;set;}
public int ProjectId {get;set;}
public Project Project {get;set;}
}
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
}
我想做一些复杂的计算来计算每月的时间表。因为我无法访问 Employee 实体中的数据库,所以我在 EmployeeService 中计算了 TimeSheet。
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public List<CalculatedMonth> GetMonthlyTimeSheet(int employeeId) {
var employee = _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
如果我想获得 TimeSheet,我需要注入 EmployeeService 并调用 GetMonthlyTimeSheet。
所以 - 我最终在我的服务中使用了很多 GetThis() 和 GetThat() 方法,尽管这些方法非常适合 Employee 类本身。
我想要实现的是:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeRepository.Get(employeeId);
return employee.GetTimeSheets();
}
...但为此我需要确保 TimeEntries 列表是从数据库中填充的(EF Core 不支持延迟加载)。我不想.Include(x=>y) 在每个请求中都包含所有内容,因为有时我只需要员工的姓名而不需要时间条目,这会影响应用程序的性能。
谁能指出如何正确构建这个的方向?
编辑: 一种可能性(来自第一个答案的 cmets)是:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
if (TimeEntries == null)
throw new PleaseIncludePropertyException(nameof(TimeEntries));
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public Employee GetEmployeeWithoutData(int employeeId) {
return _db.Employee.Single();
}
public Employee GetEmployeeWithData(int employeeId) {
return _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeService.GetEmployeeWithData(employeeId);
return employee.GetTimeSheets();
}
【问题讨论】:
-
避免进入贫血域模型的第一步是让你的设置器
private并创建适当的对象构造函数,并进行参数验证。此外,在使用 EF 时,如果您的public构造函数不是像我建议的那样无参数,则您至少需要一个protected构造函数。 -
我认为考虑如何对模型进行单元测试是可行的。恕我直言,使代码可测试通常是梳理设计问题及其解决方案的绝佳方式。例如,您是否很高兴能够根据上述设计测试(单元或集成)您的
EmployeeService? -
@Jetro223 正如您所介绍的那样,无论您是否愿意,您的模型是贫血。
标签: c# architecture asp.net-core domain-driven-design entity-framework-core