ドメインモデルと関連データ(貧血ドメインモデル)

architecture asp.net-core c# domain-driven-design entity-framework-core

質問

私は現在、ASP .NET Core 1.0でEntity Framework Coreを使用しています。私はデータベースからのデータといくつかの複雑な計算があり、私は貧血ドメインモデル( http://www.martinfowler.com/bliki/AnemicDomainModel.html構築せずに Dependency Injection 使って適切なアーキテクチャを構築する方法がわかりません

(簡体字)例:

私は以下のエンティティを持っています:

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を計算するために複雑な計算をしたい。私はEmployeeエンティティ内のデータベースにアクセスすることはできませんので、私は中にタイムシートを計算する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;
    }
}

タイムシートを取得したい場合は、EmployeeServiceを注入してGetMonthlyTimeSheetを呼び出す必要があります。

だから、このメソッドはEmployeeクラス自体に完全に適合しますが、私のサービス内には多くのGetThis()メソッドとGetThat()メソッドがあります。

達成したいのは次のようなものです:

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)

誰も私がどのようにこれを正しく設計する方向に向けることができますか?

編集: 1つの可能性(最初の回答のコメントから):

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員のタイムシートの整合性を保護する責任がありますか?そうでなければ、このデータはEmployeeクラスに属しません。

レイジーローディングはCRUDモデルではうまくいくかもしれませんが、集合体を設計するときには、できるだけ小さくて粘着性があるため、通常はパターンの反パターンとみなされます。

タイムシートの計算結果に基づいてビジネス上の決定を下していますか?保護すべき不変条件はありますか?失効したタイムシートデータが決定された場合は重要ですか?これらの質問に対する答えが「 いいえ」であれば、あなたの計算は実際には何の質問でもありません

サービスオブジェクトへのクエリの配置は問題ありません。これらのサービスオブジェクトは、ドメインモデルの外側(例えばアプリケーション層内)に存在することさえありますが、それに続く厳密なルールはありません。また、計算を処理するために必要なデータにアクセスするためにいくつかの集計をロードすることもできますが、通常はデータベースに直接アクセスする方が良いでしょう。これにより、読み込みと書き込み(CQRS)をよりよく分離できます。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ