2013-09-16 33 views
26

AngularJS、C#、ASP.Net Web API、およびFluent NHibernateを使用してWebアプリケーションを構築しています。 DTOを使用してプレゼンテーション層(角度表示)にデータを転送することにしました。 私は、DTOの一般的な構造化と命名に疑問を抱いていました。 私のシナリオを示す例です。DTO命名規則、モデリングおよび継承

1)だけでIDと名前 :、私の見解で/プレゼンテーション層は、私のようなお客様のさまざまな味を取得する必要が

public class Customer 
    { 
     public virtual int Id { get; set; } 
     public virtual string Name { get; set; } 
     public virtual Address Address { get; set; } 
     public virtual ICollection<Account> Accounts { get; set; } 
    } 

今: は、私はのように見えるドメインエンティティと呼ばれる顧客を持っているとしましょう2)ID、名前と 3アドレス)ID、名前、住所、私はこれを達成するためのDTOのセットを作成している

アカウント:

public class CustomerEntry 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class CustomerWithAddress : CustomerEntry 
{ 
    public AddressDetails Address { get; set; } 
} 

public class CustomerWithAddressAndAccounts : CustomerWithAddress 
{ 
    public ICollection<AccountDetails> Accounts { get; set; } 
} 
を0

AddressDetailsとAccountDetailsは、対応するドメインエンティティのすべてのプロパティを持つDTOです。

これはクエリとデータの取得に適しています。問題は、挿入と更新のために何を使用するかということです。新しい顧客レコードの作成時には、名前と住所は必須であり、アカウントはオプションです。つまり、すべての顧客プロパティを持つオブジェクトが必要です。したがって、混乱:

1)挿入と更新には何を使用しますか? CustomerWithAddressAndAccounts DTOにはすべてが含まれていますが、名前は挿入/更新に使用するのが少し面倒です。

2)私は別のDTOを作成しますか?私がそうした場合、新しいDTOは正確にCustomerWithAddressAndAccountsのように重複しませんか?

3)上記のDTO継承strcutureは、要件に適しているようですか?これをモデル化する他の方法はありますか?

私はこのトピックについて他の投稿を行ってきましたが、あまり進んでいませんでした。 私がピックアップしたことの1つは、クラス名に接尾辞 "DTO"を使用しないようにすることでした。 少し余分な感じがすると思います。

自分の考え

答えて

9

勧告は、あなただけのDTO例えば接尾辞各エンティティのための1つのDTOクラスを持つべきであるということです

感謝を聞くのが大好きですCustomerEntryDTOCustomerentity(ただし、選択肢や要件に応じて必ず継承階層を使用できます)。

さらに、抽象的なDTOBase種類の基本クラスまたはインターフェイスを追加します。子供のDTOに含まれる各住所、口座、およびその他の財産について、そのような深い継承階層を使用しないでください。

[Serializable] 
public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public AddressDetails Address { get; set; } //Can remain null for some Customers 
    public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer 
} 

また、あなたのDTO プロセス境界を越えて渡されることがシリアライズ可能でなければなりません。むしろ、同じCustomerEntryDTOクラス(可能ならば)以下のように、これらの特性があります。記事の下にDTOパターンのよりについては

、参照してください。

Data Transfer Object

MSDN

編集:あなたがワイヤ上で特定のプロパティを送信したくない場合は (条件付きでこれ以上調べる必要があることはわかっていますが)などの属性を使用してシリアライゼーションメカニズムから除外できます(ただし、フィールドでのみ動作し、プロパティでは機能しません。プロパティで使用する回避策の記事:NonSerialized on propertyを参照してください)。 ExcludeFromSerializationAttributeのような独自のカスタム属性を作成し、特定の規則/条件に基づいてワイヤを介して毎回送信したくないプロパティに適用することもできます。 も参照してください。Conditional xml serialization

編集2:1つのCustomerEntryDTOクラスに異なる特性を分離するための 用途のインタフェース。 GoogleまたはMSDNのインターフェイス分離の原則を参照してください。私は後でサンプルの説明をしようとします。

+0

ご返信ありがとうございます。複数のDTOクラスを使用する動機の1つは、DTOが何のために使用されているかを定義する上でもう少し表現力豊かであることでした。また、IDと名前だけが必要な場合は、本当に完全な本物のCustomerEntryDTO(あなたが記述したもの)を電信線で送信する必要がありますか? – Sennin

+0

@センニン私はあなたのコメントに基づいて私の答えを編集しましたが、私の答えはまだあなたのために不完全であると思います。上記のコメントを追加するために後で編集してもよいでしょうか。 – VS1

+0

@Sennin plsは私の編集2を参照してください。 – VS1

0

あなたのアイテム1では、挿入と更新のために、コマンドパターンを使用することをお勧めします。 CQRSによると、DTOは必要ありません。私は、挿入および更新のために何を使うのですかblogs.msdn.com

+0

あなたは依然として質問の側にDTOが必要なので、良い答えではありません。 –

0

経由 CQRS — basic patterns :このスキーマを考えてみましょうか?

  1. サービスの操作は通常の業務に非常に近い関係で定義されています。ビジネス言語は "挿入"と "更新"の観点からは言いませんし、サービスも行いません。

  2. 顧客管理サービスには、顧客名とその他のオプションのパラメータが必要な操作がある可能性があります。Register

私は別のDTOを作成するのですか?

はい、別のDTOを作成する必要があります。

時々、サービス運用契約は十分であり、特定の操作のために別のDTOを定義する必要はありません。

function Register(UserName as String, Address as Maybe(of String)) as Response 

しかし、それだけのためにも、別のDTOクラスを定義することをお勧めしますほとんどの時間単一のサービスの操作:それは同じフィールドを持っているので

class RegisterCommand 
    public UserName as String 
    public Address as Maybe(of String) 
end class 

function Register(Command as RegisterCommand) as Response 

RegisterCommand DTOはCustomerWithAddress DTOと非常によく似ていてもよいが、実際にはこれら2つのDTOは非常に異なる意味を持っているし、お互いを代用しないでください。

たとえば、CustomerWithAddressにはAddressDetailsが含まれていますが、単純なStringのアドレス表記では、顧客を登録するのに十分な場合があります。

サービス操作ごとに別々のDTOを使用すると、書き込みに時間がかかりますが、保守が容易になります。