域模型和相关数据(贫血领域模型)

Jet*_*223 5 c# architecture domain-driven-design entity-framework-core asp.net-core

我目前正在使用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;}
}
Run Code Online (Sandbox Code Playgroud)

我想做一些复杂的计算来计算每月的TimeSheet.因为我无法访问Employee实体中的数据库,所以我在a中计算TimeSheet EmployeeService.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我想获取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();
}
Run Code Online (Sandbox Code Playgroud)

...但为此我需要确保从数据库中填充TimeEntries列表(EF Core不支持延迟加载).我不想.在每个请求中包含(x => y)所有内容,因为有时我只需要没有时间条件的员工姓名,这会影响应用程序的性能.

有人能指出我如何正确地构建这个方向吗?

编辑: 一种可能性(来自第一个答案的评论)将是:

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();
}
Run Code Online (Sandbox Code Playgroud)

Ily*_*dik 0

如果我正确理解你的问题,你可以使用一个技巧,将服务注入到你的实体中,以帮助它完成工作,例如:

public class Employee()
{
    public object GetTimeSheets(ICalculatorHelper helper)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在保存员工的服务中,您将在构造函数中获取它并传递给员工类进行计算。该服务可以是一个外观,例如用于获取所有数据并执行初始化或您真正需要的任何内容。

至于 TimeEntries,您可以使用如下函数获取它们:

private GetTimeEntries(ICalculationHelper helper)
{
   if (_entries == null)
   {
       _entries = helper.GetTimeEntries();
   }
   return _entries;
}
Run Code Online (Sandbox Code Playgroud)

当然,这取决于您的缓存策略等,这种模式是否适合您。

就我个人而言,我发现使用贫血类相当容易,并且服务中有很多业务逻辑。我确实在对象中放入了一些内容,例如根据名字和姓氏计算全名。通常是不涉及其他服务的东西。虽然这是一个偏好问题。

  • 那么让我总结一下:您建议该类接收每个方法的一些依赖项,这有助于它加载其属性?我可以很容易地看到这种失控并变成一个成熟的意大利面条代码。 (2认同)