域模型和相關數據(貧血域模型)

architecture asp.net-core c# domain-driven-design entity-framework-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;}
}

我想做一些複雜的計算來計算月度TimeSheet。因為我不能僱員實體中訪問數據庫I計算的時間表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;
    }
}

如果我想獲取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不支持延遲加載)。我不想。在每個請求中包含(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();
}

熱門答案

不要嘗試解決聚合的查詢問題。您的聚合用於處理命令和保護不變量 。它們圍繞一組數據形成一致性邊界。

Employee像是否負責保護員工時間表的完整性?如果沒有,則此數據不屬於Employee類。

對於CRUD模型,延遲加載可能沒問題,但是當我們設計聚合時通常認為是反模式,因為它們應該盡可能小而且內聚。

您是否根據時間表中的計算結果做出業務決策?有沒有保護的不變量?如果決定是否陳舊的時間表數據,這是否重要?如果這些問題的答案是否定的,那麼您的計算實際上只不過是一個查詢。

在服務對像中放置查詢很好。這些服務對象甚至可能存在於域模型之外(例如,在應用程序層中),但沒有嚴格的規則可循。此外,您可以選擇加載一些聚合以訪問處理計算所需的數據,但通常最好直接進入數據庫。這樣可以更好地分離讀寫(CQRS)。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因