2015-11-08 17 views
5

現在、ASP.NET MVCプロジェクトではonion arcitectureを使用するようにリファクタリングしています。今後の開発ニーズに適しているようです。タマネギのアーキテクチャでのビューモデル/ DTOの配置

私は私が使用する必要があると思うレイヤを設定していると私の解決策は、次のようになります

:だから

enter image description here

、基本的に私は理解してきたように、ClientName.Coreプロジェクトはいずれも持つべきではありません他のプロジェクトへの参照はまったくありません。 ClientName.InfrastructureにはClientName.Coreへの参照が必要です。 ClientName.CoreのInterfacesフォルダはClientName.Infrastructureプロジェクトにあるサービスを定義し、DbContextとドメインエンティティは分離されているため、エンティティのみがコアプロジェクトに含まれます。

私が壁に向かって頭を動かしたところでは、ClientName.Infrastructureプロジェクトはドメインエンティティをそれを呼び出すクライアントに返してはいけないということでした。これは、コアプロジェクトとタマネギの原則に違反するUIとの間の参照を作成します。これを回避する方法は、私が読んだとおり、代わりにインフラストラクチャサービスがDTOを返すようにすることです。しかし、PersonServiceクラスから返されたPersonDtoの場合、PersonDtoオブジェクトは、ClientName.Coreプロジェクトがそれを認識する必要があります。

質問:UI /クライアントに使用されるDTO/ViewModel /その他のモデルは、どこに配置すればよいですか?これらのモデルを保持する別のクラスライブラリを作成し、UI、インフラストラクチャ、およびコアプロジェクトの両方で参照できるようにしますか?私は事前にこの;-)

おかげについて少し困惑しているよう

すべてのヘルプ/ヒント

が大幅に高く評価されます。 Euphoricsの回答に基づいて

EDIT

、私はいくつかのフォローアップの質問を右、多分それを得た場合だけチェックするために、ここで例のコードを書いています。

だから基本的に、私のClientName.Core層に、私はつまり、ビジネスロジックが含まれている私のエンティティを持っているPersonFirmエンティティは次のようになります。

(Exists in ClientName.Core/Entities) 
public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Firm Firm { get; set; } 
} 

(Exists in ClientName.Core/Entities) 
Public class Firm 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public IEnumerable<Person> Employees { get; set; } 

    public IEnumerable<Person> GetEmployeesByName(string name) 
    { 
     return Employees.Where(x => x.Name.Equals(name)); 
    } 

    public void AddEmployee(Person employee) 
    { 
     Employees.Add(employee); 
    } 

    public void CreateFirm(Firm firm) 
    { 
     // what should happen here? Using entity framework, I have no reference to the DbContext here... 
    } 
} 

(Exists in ClientName.Infrastructure/Services) 
public class FirmService : IFirmService 
{ 
    private readonly IDbContext _context; 

    public FirmService(IDbContext context) 
    { 
     _context = context; 
    } 

    public Firm GetById(int firmId) 
    { 
     return _context.Firms.Find(firmId); 
    } 

    // So basically, this should not call any domain business logic? 
    public void CreateFirm(CreateFirmFormViewModel formViewModel) 
    { 
     Firm firm = new Firm() 
     { 
      Name = formViewModel.Name; 
     } 

     _context.Firms.Add(firm); 
     _context.SaveChanges(); 
    } 

    public IEnumerable<Person> GetEmployeesByName(int firmId, string name) 
    { 
     Firm firm = _context.Firms.Find(firmId); 
     return firm.GetEmployeesByName(name); 
    } 
} 

は私がすべての読み取りクエリがなければならないことを修正アムエンティティに直接定義されています(Entity Frameworkを使用しているのでエンティティの拡張として)、作成/更新/削除はインフラストラクチャ層のサービスでのみ行われますか?

FirmServiceインターフェイス/クラスに読み取り(つまり、IEnumerable<Person> GetEmployeesByName(int firmId, string name)メソッド)する必要がありますか?

おかげで再び

答えて

2

まず:-)、あなたがPersonServiceからPersonを返すが、IPersonServiceからされていません。これは概念的に大きな違いです。 PersonServiceはIPersonServiceが定義するものだけを実装します。どのインタフェースやオブジェクトが使用されているかは気にしません。

要するに、コアプロジェクトはビジネスエンティティにすべてのビジネスロジックを含める必要があります。あなたが実際のロジックを持っていなければ、単純なDTOになります。次に、Infrastructureはデータベースからそれらのエンティティを保存/ロードする責任があります。独自のエンティティを持つモデルを作成する場合、またはコアで定義されたものを再利用する場合は、Infrastructureの実装の詳細です。同時に、UI(またはWeb)プロジェクトはCoreプロジェクトのエンティティで動作しますが、永続性がどのように発生するかは気にしません。それはちょうど "ビジネスをやりたい"と思っています。

ここで重要な点は、コア(またはビジネスロジック)がUIまたはデータベースコードを含まずに自動テスト可能であることです。あなたがそれを達成できるのであれば、いくつかのDTOがどこにあるかは関係ありません。

編集:

これはハード取得し始めています。デザイン要件が矛盾しています。一方では、明確なドメイン設計があります。もう一方では、EFを使用してモデルを永続化する必要があります。 1つのことは明らかです。ドメインモデルを妥協して捻ってEFで使用できるようにすることです。

今具体的な問題があります。最初は会社の創設です。ここでは、あなたはドメインによって理解されるように "新会社"の間に葛藤があります。例えば。新しい会社に有効な名前が付いていることを確認します。もう一方では、インスタンスを作成し、EFにインスタンスを認識させたいとします。私がそれを行う方法は、Firmクラスからを削除し、新しいFirm(例:名前だけ)を作成し、新しく作成した会社を返すのに必要なパラメータだけを受け入れるようにCreateFirmIFirmServiceに変更することです。また、リポジトリがドメインを呼び出すべきではないという考え方は間違っています。たとえば、リポジトリは、作成した会社が有効であるかどうかを検証するためにドメインを呼び出すことができます。そうでない場合は、EFに追加しないでください。

私が見る第2の問題は、社内での社員コレクションの維持です。これはドメインには最適ですが、(このシナリオでは遅延読み込みがうまくいくと思わない限り)永続性のために災害です。再び。 「会社は従業員の集まり」というドメイン要件を満たす方法と、エンティティをデータベースに保持する能力は、単純な方法ではありません。最初の選択肢は、このコレクションを持たずに、それを適切に実装できるIFirmServiceに移動することです。第3の選択肢は最も極端です。そして、それは、すべての "get"を抽象メソッドにしながら、インフラストラクチャプロジェクトでその実装を作成し、具体的なインスタンスが持つEFコンテキストを使用してgetメソッドを実装すると、Firmを抽象クラスにすることです。また、これはインフラストラクチャに具体的なインスタンスFirmが作成されている場合にのみ可能です。

私は個人的に3番目のオプションが好きです。なぜなら、それはメソッドを素早く密接に保つからです。しかし、いくつかのEFの純粋主義者は私に同意しないかもしれません。

+0

こんにちは@ユーフォリック、あなたの答えをありがとう。私はちょうど私が正しいことを確認するために、いくつかの簡単なコードといくつかのフォローアップの質問で私の質問を更新しました。 –

関連する問題