2012-08-14 9 views
9

私は、ドメイン駆動型設計の価格を使用して私のASP.NET MVCアプリケーションを書き直しに取り組んでいます。私は自分のUserエンティティを検証しようとしています。これまでは、基本的な規則(ユーザー名とパスワードが空白でない文字列など)を検証することができました。しかし、ルールの1つとして、ユーザー名が一意であることを確認する必要があります。しかし、私はこれを行うためにデータベースにアクセスする必要があります。つまり、IUserRepositoryを自分のUserエンティティに挿入する必要があります。DDDドメインモデル複雑な検証

public class User 
{ 
    private readonly IUserRepository _userRepository; 
    public User(IUserRepository repo) 
    { 
     _userRepository = repo; 
    } 

    public override void Validate() 
    { 
     //Basic validation code 
     if (string.IsNullOrEmpty(Username)) 
      throw new ValidationException("Username can not be a null or whitespace characters"); 
     if (string.IsNullOrEmpty(Password)) 
      throw new ValidationException("Password can not be a null or whitespace characters"); 

     //Complex validation code 
     var user = _userRepository.GetUserByUsername(Username); 
     if (user != null && user.id != id) 
      throw new ValidationException("Username must be unique") 
    } 
} 

しかし、これは...間違っているようです。私のエンティティを私のリポジトリに依存させることは、悪い考えのように思える(私が間違っていれば私を修正する)。しかし、エンティティに検証コードを持つことは理にかなっています。複雑な検証コードを置くのに最適な場所はどこですか?

+2

また、[この回答を見る](http://stackoverflow.com/a/9676307/706456) – oleksii

答えて

8

しかし、これは...間違っているようです。私のエンティティを私のリポジトリに依存させることは、悪い考えのように思える(私が間違っていれば私を修正する)。

一般に、リポジトリへの依存は「間違っていません」、時には避けられません。しかし、私はそれが例外でなければならないと考え、可能な限り避けるべきです。あなたのシナリオでは、この依存関係を再考するかもしれません。あなたがそれについて考えるなら、エンティティは他のエンティティについて知りませんので、 '一意性'はエンティティ自身の責任ではありません。ではなぜエンティティにこのルールを適用させるのですか?

エンティティに検証コードがあることは意味があります。複雑な検証コードを置くのに最適な場所はどこですか?

「検証」が過度に行われている可能性があります。私は '検証'メソッドを取り除き、オブジェクトが最初に '無効な'状態にならないようにします。数ヶ月前の私はanswered同様の質問です。

ここで、一意性ルールに戻ります。私はこれがDDDの「リーク」の例の1つだと思います。このビジネスルールの実施は純粋にドメインコードで表現できません。それ以外の場合はクラッシュします、新しいユーザーを追加する前に、それが明示的に一意性を確認する必要があることを知っているだろう

// repository 
interface Users { 
    // implementation executes SQL COUNT in case of relation DB 
    bool IsNameUnique(String name); 

    // implementation will call IsNameUnique and throw if it fails 
    void Add(User user); 
} 

クライアントコード:私はこのようにそれに近づくでしょう。この組み合わせにより、ドメイン・コード内にビジネス・ルールが適用されますが、通常は十分ではありません。追加の強制レイヤーとして、データベースにUNIQUE制約を追加するか、明示的なロックを使用することができます。

4

しかし、これはありません、それは全く間違っていないのです

...よく間違っているようです。ドメインモデルをリポジトリに依存させることは、まったく問題ありません。それに加えて、あなたはあなたのリポジトリをインターフェイスの後ろに抽象化しました。これはさらに優れています。

コンストラクタインジェクションを使用しないでください。

私は@oleksiiに同意
public class User 
{ 
    public void Validate(IUserRepository repo) 
    { 
     //Basic validation code 
     if (string.IsNullOrEmpty(Username)) 
      throw new ValidationException("Username can not be a null or whitespace characters"); 
     if (string.IsNullOrEmpty(Password)) 
      throw new ValidationException("Password can not be a null or whitespace characters"); 

     //Complex validation code 
     var user = repo.GetUserByUsername(Username); 
     if (user != null && user.id != id) 
      throw new ValidationException("Username must be unique") 
    } 
} 
+0

あなたの答えをありがとう。問題は、ユーザーを構築するためにIUserRepositoryを実装する必要があることです。つまり、IoCを使用してエンティティの依存関係を注入する必要があります。これは、オブジェクトを構築するときに属性を初期化することを利用しているので、特に価値があるよりもコードが多いようです。例var user = new User {Username = "Admin"}; –

+0

この場合、コンストラクタインジェクションは使用しないでください。これが唯一のものであれば、リポジトリをValidateメソッドに渡します。 –

1

using the specification patternがより良いアプローチである:それはそれを必要とするだけである場合、Validateメソッドにリポジトリを渡します。バリデーションにはさまざまな意味合いがありますので、この懸念を分割することは意味があります。

8

これらのタイプの状況で使用するパターンは、このタイプの検証ロジックをアプリケーションサービスに配置することです。Userエンティティは、ユーザーの有効性ではなく、それ自身の有効性についてのみ責任を負うため、これはある程度まで意味を持ちます。ユーザーを作成するアプリケーション・サービス・メソッドは、これをlooklikeことができます。

public User CreateUser(string userName) 
{ 
    if (this.userRepository.Exists(userName)) 
    throw new Exception(); 
    var user = new User(userName); 
    this.userRepository.Add(user); 
    return user; 
} 

アプリケーションサービスは関係なく、あなたがいないのDDDを採用したりしているかどうかのがあり、したがって、DDDが与えるときにフォールバックするには良い場所である抽象化です摩擦。

関連する問題