12

リポジトリベースのソリューションの基礎となるLINQ TO SQLの使用。次のように私の実装は次のとおりです。リポジトリパターンのサブレコードのロード

WhereSomethingEqualsTrue() ... 

私の質問は以下のとおりである:

IRepository

をそれから私のような結果を照会するために使用されている拡張メソッドを持っている
FindAll 
FindByID 
Insert 
Update 
Delete 

My UsersリポジトリにはN個の役割があります。役割を管理する役割リポジトリを作成しますか?私はこのルートに行くと、数十のリポジトリ(Joinテーブルを除いてほとんどテーブルあたり1つ)を作成することになるだろうと心配しています。テーブルあたりのリポジトリは共通ですか?

答えて

31

各エンティティに上記のIRepositoryインターフェイスのメソッドリストがあるように、1つのエンティティ(テーブル)に固有のリポジ​​トリを構築する場合、実際に何をしているかはActive Recordの実装ですパターン。

にはテーブルごとに1つのリポジトリがありません。ドメインモデル内の集約と、その上で実行する操作を識別する必要があります。ユーザーとロールは通常緊密に関連しており、通常はアプリケーションが連携して操作を実行します。これは、ユーザーと密接に関連するエンティティを中心とした単一のリポジトリを必要とします。

あなたの投稿から推測しているのは、seen this exampleです。この例の問題は、すべてのリポジトリが基本レベルで同じCRUD機能を共有していることですが、これを超えてドメイン機能のいずれかを実装するわけではありません。その例のすべてのリポジトリは同じように見えますが、実際には実際のリポジトリはすべて同じに見えるわけではありませんが(インタフェースはまだ必要ですが)、それぞれのリポジトリに関連付けられた特定のドメイン操作があります。

あなたのリポジトリのドメイン操作がより多くのようになります。

userRepository.FindRolesByUserId(int userID) 
userRepository.AddUserToRole(int userID) 
userRepository.FindAllUsers() 
userRepository.FindAllRoles() 
userRepository.GetUserSettings(int userID) 

等...

これらのアプリケーションは、基礎となるデータに対して実行したい、とリポジトリはそれを提供しなければならないことを具体的な操作です。リポジトリは、ドメインで実行するアトミック操作の集合を表していると考えてください。一般的なリポジトリを介していくつかの機能を共有し、拡張メソッドで特定のリポジトリを拡張することを選択した場合、それはあなたのアプリケーションにうまくいくかもしれない1つのアプローチです。

操作を完了するためにアプリケーションが複数のリポジトリをインスタンス化する必要がある場合は、rareである必要があります。その必要はありますが、アプリケーションのすべてのイベントハンドラが、ユーザーの入力を受け取り、入力が表すエンティティを正しくインスタンス化するために、6つのリポジトリをゆがんでいる場合は、おそらく設計上の問題があります。

+1

さて、そこに行くよ。毎日何かを学ぶ。私自身のアプローチを調整する必要があります:-) – Dylan

+0

うん。私はこの答えで何かを学びます。私はいくつかのリポジトリを持つことが理にかなっていたが、各リポジトリが集約の周りに構築されるべきであることを知らなかった。完全に意味をなさない –

+0

優秀な投稿。 –

4

テーブルごとのリポジトリは共通ですか?

いいえ、ただし、まだ複数のリポジトリを作成できます。集約の周りにリポジトリを構築する必要があります。

また、あなたはすべてのリポジトリから抽象一部の機能することができるかもしれない...と、あなたはLINQのツーSQLを使用しているので、おそらく...

あなたはどの基地リポジトリを実装することができますすることができます一般的な方法では、この共通の機能をすべて実装しています。

次の例は、この点を証明するためだけのものです。それはおそらく多くの改善が必要です...

interface IRepository<T> : IDisposable where T : class 
    { 
     IEnumerable<T> FindAll(Func<T, bool> predicate); 
     T FindByID(Func<T, bool> predicate); 
     void Insert(T e); 
     void Update(T e); 
     void Delete(T e); 
    } 

    class MyRepository<T> : IRepository<T> where T : class 
    { 
     public DataContext Context { get; set; } 

     public MyRepository(DataContext context) 
     { 
      Context = Context; 
     } 

     public IEnumerable<T> FindAll(Func<T,bool> predicate) 
     { 
      return Context.GetTable<T>().Where(predicate); 
     } 

     public T FindByID(Func<T,bool> predicate) 
     { 
      return Context.GetTable<T>().SingleOrDefault(predicate); 
     } 

     public void Insert(T e) 
     { 
      Context.GetTable<T>().InsertOnSubmit(e); 
     } 

     public void Update(T e) 
     { 
      throw new NotImplementedException(); 
     } 

     public void Delete(T e) 
     { 
      Context.GetTable<T>().DeleteOnSubmit(e); 
     } 

     public void Dispose() 
     { 
      Context.Dispose(); 
     } 
    } 
+2

いいえ、各リポジトリは1つの集約ルートの永続性ロジックをカプセル化する必要があります –

+0

@Johannesはい、どうですか? –

+0

クライアントクラスが "T FindByID(Func 述語)"という関数をどのように使用するか教えてください。私はコードデモを待っています。 – Lijo

1

私にとって、リポジトリパターンはデータアクセス方法論の周りに薄いラッパーを貼ることです。あなたのケースではLINQをSQLに変換しますが、NHibernateは他の人に手渡しします。私が自分自身でやっていることは、テーブルあたりのリポジトリを作成することです(これはbrunoリストのように非常に簡単です)。それは物事を見つけ、CRUD操作を行う責任があります。

しかし、私は、ヨハネスが言及しているように、集約根をより多く扱うサービスレベルを持っています。 GetExistingUser(int id)のようなメソッドを持つUserServiceがあります。これは内部的にUserRepository.GetById()メソッドを呼び出してユーザーを取得します。あなたのビジネスプロセスでGetExistingUser()によって返されたユーザークラスが、ほとんど常にUser.IsInRoles()プロパティを満たす必要がある場合は、UserRepository RoleRepositoryの両方に依存します。

public class UserRep : IUserRepository 
{ 
    public UserRep(string connectionStringName) 
    { 
     // user the conn when building your datacontext 
    } 

    public User GetById(int id) 
    { 
     var context = new DataContext(_conString); 
     // obviously typing this freeform but you get the idea... 
     var user = // linq stuff 
     return user; 
    } 

    public IQueryable<User> FindAll() 
    { 
     var context = // ... same pattern, delayed execution 
    } 
} 

個人的に私は、リポジトリのクラスが内部スコープになるだろう:SQLビットにあなたのLINQでこのような何かを構築することでしょう

public class UserService 
{ 
    public UserService(IUserRepository userRep, IRoleRepository roleRep) {...} 
    public User GetById(int id) 
    { 
     User user = _userService.GetById(id); 
     user.Roles = _roleService.FindByUser(id); 
     return user; 
} 

userRepとroleRep:擬似コードでは、このようなものを見ることができますUserServiceと他のXXXXXServiceクラスを公開して、サービスAPIの消費者を正直に保つようにしてください。だから、私はリポジトリがデータストアとの会話の行為と密接に関連していると見ていますが、サービス層はビジネスプロセスのニーズにより密接に関連しています。

実際に必要なものを吐き出すサービスメソッドを構築するのではなく、オブジェクトとそのすべてのものに対するLinqの柔軟性を本当に思っていることがよくあります。などユーザーLINQは適切な場所ですが、リポジトリにすべての作業を行わないようにしてください。

public IList<User> ActiveUsersInRole(Role role) 
{ 
    var users = _userRep.FindAll(); // IQueryable<User>() - delayed execution; 
    var activeUsersInRole = from users u where u.IsActive = true && u.Role.Contains(role); 
    // I can't remember any linq and i'm type pseudocode, but 
    // again the point is that the service is presenting a simple 
    // interface and delegating responsibility to 
    // the repository with it's simple methods. 
    return activeUsersInRole; 
} 

だから、少しばかりだった。私が本当に助けてくれたかどうかはわかりませんが、私のアドバイスは、拡張メソッドで余りにも気にならないようにすることです。私のために働く。

1

Wompが提案しているように、リポジトリレイヤーを記述すると、私たちはサービスレイヤーに何を配置しますか?ほとんどの場合、対応するリポジトリメソッドへの呼び出し、コントローラやコードビハインドでの使用など、同じメソッド呼び出しを繰り返す必要がありますか?これは、検証、キャッシュ、ワークフロー、認証/認可コードを記述するサービスレイヤがあることを前提としていますか?または私は基本から離れている?

関連する問題