1

集計の設計方法に問題があります。

、、およびエンティティがCompanyあります。これらはそれぞれ、独自の集約の集約ルートである必要があります。、およびエンティティはシステム全体で使用され、他の多くのエンティティから参照されるため、値オブジェクトではなく、さまざまなシナリオでアクセスする必要があります。したがって、リポジトリが必要です。Aには、、、、、、などのメソッドがあります。CityProvinceCountryCityProvinceCountryCityRepositoryFindById(int)GetAll()GetByProvince(Province)GetByCountry(Country)GetByName(string)

次の例を見てください。エンティティは、 に属する にCompany関連付けられています。CityProvinceCountry

集約ルート

ここで、いくつかの企業とその都市、州、および国を一覧表示する企業一覧ページがあるとします。

IDによる参照

エンティティがCityProvinceまたはを参照する必要がある場合はCountry、ID で行います (Vaughn Vernon の提案による)。

リポジトリからこのデータを取得するには、4 つの異なるリポジトリを呼び出してから、データを照合してビューに入力する必要があります。

var companies = CompanyRepository.GetBySomeCriteria();
var cities = CityRepository.GetByIds(companies.Select(x => x.CityId);
var provinces = ProvinceRepository.GetByIds(cities.Select(x => x.ProvinceId);
var countries = CountryRepository.GetByIds(province.Select(x => x.CountryId);

foreach(var company in companies)
{
    var city = cities.Single(x => x.CityId == company.CityId);
    var province = provinces.Single(x => x.ProvinceId == city.ProvinceId);
    var country = countries.Single(x => x.CountryId == province.CountryId);

    someViewModel = new CompanyLineViewModel(company.Name, city.Name, province.Name, country.Name);
}

これは非常にかさばり、非効率的ですが、明らかに「正しい」方法ですか?

参照による参照

エンティティが参照によって参照された場合、同じクエリは次のようになります。

var companies = CompanyRepository.GetBySomeCriteria();
someViewModel = new CompanyLineViewModel(company.Name, company.City.Name, company.Province.Name, company.Country.Name);

しかし、私が理解している限り、これらのエンティティは異なる集計に存在するため、参照によって参照することはできません。

質問

これらの集計をより適切に設計するには、他にどのような方法がありますか?

異なる集計に存在する場合でも、都市モデルを使用して会社エンティティを読み込むことはできますか? これはすぐに集計間の境界を壊すと思います。また、集計を更新する際にトランザクションの一貫性を処理する際にも混乱が生じます。

4

2 に答える 2

2

Dennis Traub は、クエリのパフォーマンスを向上させるために何ができるかを既に指摘しています。この方法は、クエリの効率が大幅に向上しますが、ビュー モデルと集計の同期を維持するために追加のコードが必要になるため、さらにかさばります。

そのアプローチが気に入らない場合、または他の理由で使用できない場合、あなたが提案している最初のアプローチが、直接オブジェクト参照を使用するよりも効果がなかったり、かさばったりするとは思いません。集合体でオブジェクトの直接参照を使用していたとしましょう。これらの集約を耐久性のあるストレージにどのように永続化しますか? データベースを使用している場合、次のオプションが思い浮かびます。

  • Company(たとえば、MongoDB などのドキュメント データベースで)非正規化テーブルを使用している場合は、既にビュー クエリに対して効果的に最適化されています。ただし、CompanyテーブルをCity, Province. 効率的ですが、かさばります。代わりに、実際のビュー モデルを永続化することを検討してください (ユース ケースごとに 1 つ)。
  • リレーショナル データベースで正規化されたテーブルを使用している場合は、Companyテーブルで外部キーを使用して、それぞれCityProvinceなどを ID で参照します。Companyビュー モデルに入力するために必要な などのフィールドを取得するために をCityクエリするProvince場合、4 つ以上のテーブルに対して JOIN を使用するか、CityProvince、 ... テーブルに対して 4 つの独立したクエリを使用することができます (例:外部キー参照に遅延読み込みを使用する場合)。
  • 非リレーショナル データベースで正規化されたテーブルを使用している場合、通常、提案されたコードとまったく同じようにアプリケーション側の結合が使用されます。一部のデータベースでは、Morphia や Datanucleus などの ORM ツールを使用するとプログラミング作業を節約できますが、内部では独立したクエリが残ります。

したがって、2 番目と 3 番目のオプションでは、ORM ソリューションにデータベース マッピングを生成させると、簡単なプログラミング作業を少し節約できますが、効率はあまり向上しません。( JOINs は適切なインデックスで最適化できますが、これを正しく行うのは簡単ではありません)。

ただし、提案したコードのように Id で参照し、プログラムによるアプリケーション側の結合を使用している場合は、ビュー モデル オブジェクトの構築とデータベース クエリを完全に制御できることを指摘したいと思います。特に、都市、州などの名前は通常、めったに変更されず、それらの数は少なく、簡単に記憶に収まります。したがって、データベース クエリのインメモリ キャッシングを広範に使用できます。また、アプリケーションの起動時にフラット ファイルから読み込まれるインメモリ リポジトリを使用することもできます。適切に実行すると、 のビュー モデルを構築するために、テーブルCompanyへの 1 つのデータベース呼び出しのみCompanyが必要になり、他のフィールドはインメモリ キャッシュ/リポジトリから取得されます。これは非常に効率的だと思います。

于 2014-02-02T11:33:57.627 に答える