26

私は現在MongoDBを試しています。私はNHibernate/SQLの考え方から移行しているので、最初はデータアクセス用のリポジトリパターンを実装しました。

ネストされたドキュメントを使い始めるまで、これはすべて問題なく見えました。今では少しミスマッチがあるように見え始めています。しかし、私はリポジトリに満足しており、リポジトリが提供する抽象化、関心の分離、およびテスト容易性が好きです。

人々はドキュメントデータベースでリポジトリパターンをうまく使用していますか?そうでない場合は、どのデータアクセス方法を使用しますか?抽象化/SoCはどうですか?

4

6 に答える 6

15

興味深い質問です。私のMongoDBの使用法では、リポジトリを持たないことを選択しました。これは、ドキュメントデータベースが読み取りストアとして使用されていたため(したがって、そこに格納されていたデータが単純化されたため)、主要なものでした。

リポジトリとは何か、抽象化の追加レイヤーからどのような利点が得られるかについて、考慮事項を取り除く必要があると思います。優れた設計では、レイヤーの数が可能な限り少なくなります。

したがって、リポジトリは、永続性の無知と、データの一般的なコンテキストで作業単位を使用する機能を提供します。また、データに対してクエリを分離してテストする能力を高めることもできます(これらは通常、クエリ可能または仕様として抽象化されているため)。

また、一部のドキュメントデータベースはすでにリポジトリパターン(RavenDBなど)を提供しているため、さらに別のレイヤーを用意する必要はありません。

したがって、リポジトリを使用することは、データがリレーショナルテーブルとして保存されるかドキュメントとして保存されるかではなく、抽象化から得られるものに関係しているように思われます。

于 2012-02-11T14:47:02.967 に答える
2

「Xを使うべきかどうか」を考えることは、「何を使うべきか」に焦点を合わせるほど生産的ではありませんか?

リポジトリパターンの代替案は何ですか、トレードオフは何ですか、そしてそれらはドメインと実装にどのように関連していますか?

リポジトリは、汎用ストア(SQLなど)に事前定義されたパターンのセットを適用するのに適しています。ドキュメントストアの場合、私の印象では、ドキュメントスキーマは、SQLベースのストアで通常見られるよりも大幅にアクセスパターンを決定します。この場合にリポジトリを実装すると、非常にリークの多い抽象化につながる可能性があり、基礎となるドキュメント構造への変更が関連するビジネスコードに1:1の影響を及ぼします。その場合、リポジトリはほとんど価値を提供しません。私にとって、ドキュメントストアは、作業単位がドキュメント(またはドキュメント+ネストされたサブドキュメント、またはドキュメントのセット)である作業単位(UoW)パラダイムに自然に適しています。

リポジトリパターンのもう1つの強みは、前述のように、ストレージメカニズムの抽象化です。トレードオフは通常、Mongoの低レベルの実装固有の機能へのアクセスの喪失です。それはあなたにとって価値のあるトレードオフですか?NHibernateはSQLと非常に緊密に結合されているため、RDBMSのすべての重要な機能に対して豊富な機能を備えています。私はMongoの同様のフレームワークを知らないので、抽象化のレベルをかなり上げることになります。

複数の同時データストアをサポートする必要がありますか?たとえば、同じデータレイヤーの抽象化を通じて、あるタイプのデータをSQLに書き込み、他のタイプのデータをMongoに書き込みますか?もしそうなら、リポジトリは良いオプションです。

ドメインと実装の詳細を提供できる場合は、検討する可能性のある特定のトレードオフにさらにドリルダウンできます。

于 2012-02-13T00:01:24.120 に答える
2

これがあなたに役立つかどうかはわかりませんが、しばらく前にAyendeRahienがRavenDBについて話しているポッドキャストを聞いていました。彼は、ドキュメントが実際にはDDD哲学の集合体にかなりよく対応していることを示唆していました。ネストされたドキュメントを使用して集合体を表し、設計上の問題が発生している場合、ネストは最善の方法ではないでしょうか。

于 2012-02-09T00:35:16.903 に答える
2

私は2年以上前からリポジトリパターンを使用して本番コードでMongoDBを使用していますが、これは時間の経過とともに本当に役に立ちました。抽象化は、テスト(メモリ内)と本番(MongoDB)に適しています。

私はJavaを使用していますが、コードは(おおよそ)次のようになります。

public interface MyStorage {

    boolean add(MyDoc doc);

    boolean update(MyDoc doc);

    boolean remove(String docId);

    boolean commit();

    MyDoc get(String docId);

    MyStorageQuery newQuery();

    List<MyDoc> query(MyStorageQuery q);

}

MyDocオブジェクトの新しいインスタンスを作成するストレージ実装ごとにファクトリがあります。テストのために、MongoDbと自分の手巻きモックの間で実装を交換します。

MongoDB実装は、次のようにBasicDBObjectを拡張するMyDocクラスを使用します。

public interface MyDoc {
  Data getData(); // let's assume this is a nested doc
  void setData(Data d);
  String getId();
  long getTimestamp();
  void setTimestamp(long time);
}

MongoDbMyDoc extends BasicDBObject implements MyDoc {
  MongoDbObject() { }
  void setId(String id) {
    this.put("_id", id);
  }
  String getId() {
    return super.get("_id");
  }
  void setData(Data d) {
    dataObj = new BasicDBObject();
    dataObj.put("someField",d.someField);
    dataObj.put("someField2", d.someField2);
    super.put("data",dataObj);
  }
  ...
}

次に、実際のストレージ実装で、​​MongoDB Javaクライアントを使用して、DBから実装のインスタンスを返します。これが私のMongoDBストレージ実装のコンストラクターです:

public MongoDbMyStorage(DB db, String collection) {
  //DB in a mongodb object (from the client library) which was instantiated elsewhere
  dbCollection = db.getCollection(collection);
  dbCollection.setObjectClass(MongoDbMyDoc.class);
  this.factory = new MongoDbMyDocFactory();
}

ここにはさらに2つのインターフェースがあります。 MyStorageQueryこれもMongoDB実装のBasicDBObjectとして実装されnewQuery()、ストレージインターフェースのを使用して生成されます。これはここでは示されていませんが、MyDocFactory基本的には、ストレージの実装が何であるかを認識し、MyDocそれに応じてインスタンスを生成するドキュメントファクトリです。

警告:
抽象化があまり意味をなさないことの1つは、MongoDBストレージによって使用されるインデックスを定義することです。私はすべてのensureIndex(...)呼び出しをコンストラクターに入れましたが、あまり一般的ではありませんが、コレクションごとのインデックスの定義はMongoDB固有の最適化であるため、それを使用できます。
もう1つは、コミットがgetLastError()コマンドを使用して実装されていることですが、私の経験ではあまりうまく機能しませんでした。明示的に変更をコミットすることはほとんどないので、問題はありません。

于 2012-02-13T03:43:00.823 に答える
0

Eric Evensは、彼のドメイン駆動設計の本の中で、リポジトリパターンについて非常に複雑で非常に優れた説明をしています。彼の定義は、リポジトリがどうあるべきか、そしてそれがどのように使われるべきかということです(私の個人的な意見では)。ここで簡単な説明を見つけることができます:リポジトリのEric Evans

基本的に、リポジトリをクライアントコードとファクトリの間の単なる仲介に保つ場合、それらは私があなたが必要としていると理解しているものに最適です。リポジトリは、クエリ/構築/検証インターフェイスを提供し、すべてのデータ取得スタッフ(接続/クエリデータベースなど)を実行する必要があります。さらに、オブジェクトを構築してクライアントに返す1つ以上の(必要に応じて)ファクトリが必要です。リポジトリ経由。

于 2012-01-14T17:37:20.240 に答える
0

適切なDDDでは集約ルートごとに1つのリポジトリが必要であるため、NoSQlデータベースでリポジトリパターンを使用する方が理にかなっていますが、RDSデータストアの制限により、開発者は通常、エンティティ/テーブルごとに1つのリポジトリオブジェクトを作成します。NoSQLデータベースを使用すると、DDDとリポジトリパターンを適切に実装できます。

于 2020-05-11T00:55:37.700 に答える