問題タブ [ddd-repositories]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
domain-driven-design - リポジトリなどの ddd ビルディング ブロックのように機能するドメイン オブジェクトの命名
名前があり、オブジェクトのように聞こえますが、5 つの主要な DDD ビルディング ブロックの 1 つの責任と重複するものが存在するドメイン モデル内の概念に遭遇した場合、このオブジェクトに名前を付けたり、設計を処理したりするためのベスト プラクティスは何ですか?実際の実装にその名前またはフレーズが含まれている場合と含まれていない場合がありますか?
より具体的な例を挙げると、DDD の精神でタイム トラッキング アプリケーションを設計していて、ドメインの専門家が「タイム ログ」と呼ぶものに遭遇したとしましょう。全従業員のパンチアウトタイム。
この情報を基に、既存の時間エントリを照会し、新しいまたは修正された時間ログ エントリを永続化できる TimeLog という名前のクラスが作成された場合、そのようなクラスが実際に DDD リポジトリの役割を果たしていると最初に考えました。簡単にするために、さまざまな議論とリファクタリングの後、ログエントリは本質的にそれ自体の集約ルートであり、対応するリポジトリが必要であるという結論に達したと仮定します。
ここで、ユビキタス言語の DDD の概念により近いと思われるTimeLogという名前をリポジトリに付けるか、 TimeLogEntryRepositoryと呼ぶかのオプションが残されています。これは、クエリ/永続化する集約ルートの後にリポジトリを命名するためのより一般的な規則に適合しているようです。私は TimeLog を使用するという考えに傾倒しています。これは、ドメイン モデルで TimeLog が果たす実際の役割をより説明し、ドメインの専門家に設計を伝えるのに役立つはずだからです。一方、TimeLogEntryRepository を使用するという選択は、既存の DDD 規則に従うため、開発者が設計を理解しやすくなります。妥協案として、TimeLog の命名を使用することもできますが、すべてのリポジトリに IRepository インターフェイスを実装するか、共通のリポジトリ基本クラスから継承させて、開発者がドメイン モデルを構成する他のリポジトリ クラスを見つけて区別できるようにします。
このような場合のベストプラクティスは何ですか? サービスは、開発者が SomeComplexActivityService のように「サービス」サフィックスを使用して通常名前を付ける典型的な DDD ビルディング ブロックの別の部分であるため、おそらく同じタイプの問題がサービスで発生していることがわかりますが、エンティティと値オブジェクトの場合、これは実際には問題ではありません. 私は特に、DDD の経験が豊富な他の人が何を言わなければならないかを知りたいと思っています。
linq - EF 4.1 + LINQでDDD集約ルートリポジトリを使用する必要がありますか?
DDD Evansを読み、C#とEntity Framework 4.1+LINQを使用して集約ルートリポジトリの設計を実験しています。
ただし、DBに送信される実際のクエリが心配です。私はSQL2008R2を使用しており、SQL Profilerを実行して、LINQコードに応答してDBが何を行っているかを調べています。
PersonとEmailAddressを使用した単純な2エンティティの設計について考えてみます。1人の人は0から多数のEmailAddressesを持つことができ、EmailAddressは正確に1人の人を持つ必要があります。Personは集約ルートであるため、電子メールアドレスのリポジトリは存在しないはずです。電子メールアドレスは、Personリポジトリから選択する必要があります(DDD Evansによる)。
比較のために、メールアドレス用に一時的なリポジトリを設定しています。次のコード行:
...プロファイラーに従ってクリーンなSQLクエリを実行します。
次のコードを使用して、個人リポジトリから電子メールを選択できます。
これにより、実行時に同じエンティティが取得されますが、SQLプロファイラーに異なるコマンドが表示されます。
Personから選択する上記のクエリに加えて、DBのEmailAddress行ごとに1つずつ、多数の「RPC:Completed」イベントがあります。
私のテストデータベースにはdbo.EmailAddressに14行あり、14個の異なるRPC:Completed呼び出しがあり、それぞれが異なる@EntityKeyValue1値を持っています。
dbo.EmailAddressテーブルがより多くの行を取得すると、これらのRPCの多くがデータベースで呼び出されるため、これはSQLのパフォーマンスに悪いと思います。EF 4.1 + LINQでDDD集約ルートリポジトリを使用するための別のより良いアプローチはありますか?
更新:解決済み
問題は、Allプロパティがを返していたことでしたIEnumerable<TEntity>
。これがに変更された後IQueryable<TEntity>
、LINQが起動し、Person+Email全体を一度に選択しました。ただし、AllからIQueryableを返す前に、.Include(p => p.Emails)をチェーンする必要がありました。
orm - リポジトリの予想される動作
私は ORM を書いていますが、リポジトリの予想される動作、またはより正確には、リポジトリと作業単位の間のフロンティアが不明です。私の理解では、リポジトリは次のようになります。
Fowler によると ( PoEAA、322 ページ):
リポジトリは、ドメイン レイヤーとデータ マッピング レイヤーの間を仲介し、メモリ内のドメイン オブジェクト コレクションのように機能します。[...] オブジェクトは、オブジェクトの単純なコレクションと同様に、リポジトリに追加および削除できます。
これは、次のテストが機能することを意味します (姓が Fowler である Person が永続化されていると仮定します)。
つまり、データベースへのマッピング時に、どこかで明示的な save() メソッドが呼び出されていなくても、次のクエリで元の Person を含まない正しいコレクションが返されるように、Person モデルがリポジトリによって自動的に永続化されている必要があります。
しかし、どのモデルをいつデータベースに永続化するかを決定するのは、Unit Of Work の役割ではないでしょうか。
上記の実装では、結果が変更と一致するように、リポジトリは別の find() 呼び出しを受け取ったときに以前に取得した Person を永続化することを決定する必要があります。しかし、他の find() 呼び出しが発行されなかった場合、モデルは暗黙的に永続化されませんでした。
Unit Of Work のコンテキストでは、最初にトランザクションを開始し、必要に応じてデータベースへの挿入をロールバックできるため、実際には問題になりません。しかし、このリポジトリを単独で使用すると、予期しない、予測不可能な動作につながることはありませんか?
nhibernate - DDD、リポジトリ、およびロールインターフェイス
以下の設計問題について、皆様のご意見をいただければ幸いです。
「個人」または「ビジネス」のいずれかが特定の「サービス」のプロバイダーである可能性があるモデルがあります。クラス定義の例を以下に示します。
IProviderGUIDID
_ _
担当者:IProvider
Guid Id
string FirstName
string LastName
ビジネス:
IProviderGuidId文字
列名
サービスガイド
IDIProvider
プロバイダー_
したがって、私は自分のドメインに関連する概念、「個人」、「ビジネス」、「IProvider」、および「サービス」を作成しました。私が苦労しているのは、リポジトリを作成するエンティティです。このコンテキストでは、「サービス」は集約ルートであるため、独自のリポジトリがあります。「ビジネス」は、プロバイダーでなくても意味があるため、私のコンテキストでは集約ルートでもあります。「個人」は、「プロバイダー」である場合にのみシステムに作成されます。
'Person'と'Business'のインスタンスを返すIProviderの役割のリポジトリを作成しますか。これに関する私の問題は、実装がすべての異なるタイプのIProviderを返すために複数のテーブルなどを調べる必要があるため、コードがすぐに非常に複雑になる可能性があることです。このようなアプローチでは、必要な機能を提供するために、「Person」および「Business」のリポジトリを作成して「IProvider」リポジトリに挿入する必要があります。
もう1つのアプローチは、「IProvider」インターフェースを実装する「Person」および「Business」エンティティのリポジトリを作成し、それらをその役割に参加できるようにすることです。すなわち
次に、メカニズム(つまり、IoCコンテナー)を使用して、必要に応じてIProviderRepositoryの正しい具体的な実装を選択します。たとえば、私が個人であることがわかっているプロバイダーと取引している場合、PersonRepository実装を取得できます。
もう1つのオプションは、IProviderリポジトリを実装せず、「Person」および「Business」リポジトリに固執し、サービスレイヤーで必要に応じてそれらを使用することです。
c# - RavenDbで値オブジェクトの親エンティティオブジェクトを参照します
私は最近RavenDBで遊んでいますが、少し面倒なことがあります。
一連の値オブジェクトを持つエンティティオブジェクトがあります。
Bar型のオブジェクトをメソッド/クラスに渡したいが、ある時点で親エンティティを参照したい場合が何度もあります。NHibernateの世界では、1 .. *の関係で構成すると、非常に簡単です。
ただし、RavenDbはそれがあまり好きではないため、次のようなメソッドを作成する必要があります。
それよりも
RavenDbでこれを達成する方法はありますか?
RavenDb(および一般的なドキュメントデータベース)は、エンティティの処理について異なる考え方を促進していることを認識しています。これが、リレーショナル/正規化された世界で長時間過ごしている場合は、コードの構造化方法を誰かが説明できます。より多くのドキュメントデータベースの方法で?
domain-driven-design - DDD、BoundedContexts、ドメインイベントおよびトランザクション
私は現在、DDDの原則に基づいて、製品/パーティ管理システムの概念実証を作成中です。要件の1つは、パーティデータ(顧客、再販業者)がWeb上のCRMに保存され、製品固有のデータがオンプレミスのSQLデータベースに保存されることです(以下を参照)。
CRMシステム(Webベース)
顧客(名前、住所、電子メール、連絡先設定など
が含まれます)リセラー(名前、住所、アクティブステータスが含まれます)
製品システム(オンプレミス)
BaseProduct(バニラ製品を定義)
ResellerProduct(再販業者が販売する基本製品のカスタマイズを定義)CustomerProduct(顧客が登録した製品を定義)。
私は、ソリューションを実装する方法のさまざまなアプローチについて多くの調査を行ってきましたが、すべての概念とそれらが私の問題にどのように適用されるかを理解するのに苦労しています。
私は、エリアを2つの異なる境界のあるコンテキスト、パーティーと製品に分割することから始めました。これらのコンテキストごとにドメインモデルを定義し、エンティティが他のモデルの概念を参照する場合、これらを単純なGuid IDとして残しました(つまり、製品ドメインのCustomerProductは関連するGuidのCustomerRef値を持ちます)。
次に、Web CRMへのAPI呼び出しを使用するPartyインフラストラクチャの実装と、NHibernateを使用するProductインフラストラクチャの実装を実装しました。これらのそれぞれについて、UnitOfWorkを実装して、各コンテキストでトランザクションプロセスを制御できるようにしました。アプリケーション層には、実行時に2つのコンテキストが挿入され、それらが使用されます。
例えば:
- ApplicationService.RegisterNewProduct(customerId、ProductId)
- 各作業単位のトランザクションを開始します(PartyUnitOfWork.Begin()、ProductUnitOfWork.Begin())
- 各コンテキストのリポジトリを使用して、関連するドメインオブジェクトを検索します(Party.Customer.Find(Id)、Product.ResellerProduct.Find(Id))
- ロジックを実行して、顧客が適格かどうか、製品が有効かどうかなどを判断します。
- 新しいCustomerProductを作成し、製品システムに保存します
- 各コンテキストをコミットするUnitOfWork
次に、境界のあるコンテキストをもう少し詳しく調べ始め、各コンテキストが他のコンテキストからの概念の限定された表現を持つようにアプリをリファクタリングすることを考えていましたが、そのコンテキストにのみ固有です。つまり、製品のコンテキストでは、ID、名前、アクティブステータスはあるが、連絡先の設定などはない顧客エンティティがあります。次に、DomainEventsを使用して、異なるシステム間のアクティビティを調整し、データを最新の状態に保ちます(つまり、 CRMシステムで新しい顧客が作成され、製品システムによってイベントが発生して処理され、顧客の表現が更新されます)。したがって、上記の例は変更されるため、Productコンテキストのみが使用されました。
さらに混乱させるために、「RegisterNewProduct」呼び出しも新しい顧客を作成したとしましょう。Productシステムで顧客を作成し、Partyシステムによって処理される「NewCustomer」イベントを発生させますか?
これらのアイデアについて人々のコメントを集めたいと思いますか?
ddd-repositories - バグトラッカーアーキテクチャ
DDDを念頭に置いてバグトラッカーアプリケーション(おもちゃのもの)を作成しています。Add / Delete / Saveのようなメソッドを持つBugRepositoryと、同じ種類のメソッドを持つユーザーリポジトリがあります(実際には両方ともIRepositoryから派生しています)。現在、Bugには、ユーザーのIDが格納されているDBの列である「AssignedTo」というプロパティがあります。
ここで、「FindAssignee」というメソッドが必要です。つまり、バグが誰に割り当てられているのかを知りたいのです。どこに置けばいいの?
私は言うことができると思っていました->BugRepositoryに「FindAssignee」というメソッドを追加します。しかし、それは「USER」オブジェクトを返します。それは大丈夫ですか?集約ルートのリポジトリ(この場合はバグ)は、エンティティのみを返すことになっているのではありませんか(再度バグ)?
asp.net-mvc - リポジトリに追加された集約ルートの ID を確認するにはどうすればよいですか?
次のような一般的なリポジトリ インターフェイスがあるとします。
通常、IRepository.Add() を介して追加されたアイテムの新しい ID は、何らかのバックエンド データベースによって決定されますが、トランザクション全体または作業単位が送信された後にのみ決定されます。したがって、追加されたアイテムの新しい ID を IRepository.Add() が返すのは間違っていると確信しています。リポジトリは、ID がどのように作成されるかについて、実際には何も認識すべきではありません。これは正しいです?
この場合、リポジトリに追加されたアイテムの新しい ID を他にどのように判断できますか、またはこれを行う必要がありますか? NHibernate のような ORM は、メモリ内のオブジェクトを正しい ID を持つ新しいオブジェクトに自動的に置き換えることができることを知っていますが、特定の ORM 実装を念頭に置いてリポジトリを設計しようとしています。
たとえば、顧客が注文できる Web サイトがあるとします。新しい顧客がチェックアウトを選択すると、詳細を入力するフォームに送信されます。この情報は、CustomerRepository に格納される Customer オブジェクトを作成するために使用されます。注文情報を作成する必要がありますが、注文は ID で顧客を参照する必要がありますか?
domain-driven-design - DDD リポジトリが「実際の」オブジェクトに加えてサマリー オブジェクトを使用しても問題ありませんか
以下のインターフェイスに示すように、デジタル電子書籍を保存するリポジトリを作成しているとします。このリポジトリには、書籍の実際のテキストと、書籍を識別するメタデータ (タイトル、著者、出版社、ISBN など) が保存されます。
ほとんどの場合、書籍のテキスト全体を取得したくはありません。費用がかなりかかるためです。ほとんどの場合、気にするのはメタデータだけです。たとえば、本のリストを作成したいだけかもしれません。では、オブジェクトIBookRepository
を返すメソッドを持つことも許可することは、DDD に関して許容されるのでしょうか? BookSummary
本の要約オブジェクトにはメタデータが含まれますが、本の実際の内容は含まれません。
UpdateBook(BookSummary book)
メソッドを持つことについてはどうですか?プロパティを更新したいがBook.Rating
、これを行うためにリポジトリから本の内容全体を読み取る必要がない/したくないとします。
注:遅延読み込みでORMを使用することもこれに対する解決策になることは知っていますが、遅延読み込みが使用されることを前提とせずにリポジトリを設計したいと思います
domain-driven-design - リポジトリの実装は、対応する集約のように分離する必要がありますか?
DDD を使用する場合にリポジトリを使用する利点は、オブジェクトがどのように永続化されるかを気にせずにドメイン モデルを設計できることです。また、リポジトリのさまざまな実装を簡単にスワップインおよびスワップアウトできるため、最終製品をより柔軟にすることもできます。そのため、リポジトリの実装は、SQL データベース、REST Web サービス、XML ファイル、またはデータを保存および取得するその他の方法に基づくことができます。モデルの観点からは、集計ルート オブジェクトの格納と取得に使用できるこれらの魔法のコレクションだけが存在することが期待されます。
2 つの通常のメモリ内コレクション、たとえば anIList<Order>
と anがあるIList<Customer>
場合、一方のコレクションを変更すると他方のコレクションが影響を受けるとは思いません。では、同じロジックをリポジトリに適用する必要がありますか? リポジトリの実際の実装は、実際には同じデータベースにアクセスする場合でも、互いに完全に分離する必要がありますか?
たとえば、顧客が削除されたときに対応する注文が削除されるように、Customers
テーブルとテーブルの間にカスケード オン デリートの関係を SQL データベースで設定することができます。Orders
ただし、後でSQLCustomerRepository
が に置き換えられると、この機能は壊れRESTCustomerRepository
ます。
リポジトリが互いに完全に分離されており、それに応じてリポジトリの実際の実装も分離されている必要があるという仮定の下にモデルを常に配置する必要があると考えるのは正しいですか?
では、データベースに依存するのではなく、ドメイン モデルでこれを明示的に定義する必要がありますかOrders
? 現在のとにアクセスCustomer
するメソッドを使用して言います。CustomerService.DeleteCustomer()
ICustomerRepository
IOrderRepository
リレーショナルの世界から抜け出して DDD の世界に足を踏み入れるのに苦労しているだけだと思います。私は、テーブルと PK/FK の関係の観点から物事を考えたいと思っていますが、データベースが関係していることはまったく無視する必要があります。