web-dev-qa-db-ja.com

大規模システムのEntity Framework-モデルを分割する方法は?

1000以上のテーブル、さらに数百のビュー、数千のストアドプロシージャを備えたSQL Serverデータベースを使用しています。 Entity Frameworkを新しいプロジェクトに使用することを検討しており、そのための戦略に取り組んでいます。私が悩んでいるのは、テーブルをさまざまなモデル(最初にコードを作成する場合はEDMXまたはDbContext)に分割するのに最適な方法です。私はすぐにいくつかの戦略を考えることができます:

  • スキーマで分割
    テーブルをおそらく12のスキーマに分割しています。スキーマごとに1つのモデルを実行できます。ただし、これは完全ではありません。dboは、500以上のテーブル/ビューを含む非常に大きなものになるためです。別の問題は、特定の作業単位が複数のモデルにまたがるトランザクションを実行しなければならず、複雑さを増すことですが、EFではこれをかなり簡単に行うことができると思います。
  • 意図で分割
    スキーマについて心配する代わりに、意図によってモデルを分割します。したがって、取得する粒度に応じて、アプリケーション、プロジェクト、モジュール、または画面ごとに異なるモデルを用意します。これで私が目にする問題は、UserやAuditHistoryなど、必ずすべてのケースで使用する必要がある特定のテーブルがあることです。これらをすべてのモデルに追加しますか(違反DRY思う))、またはすべてのプロジェクトで使用される個別のモデルにありますか?
  • まったく分割しない-1つの巨大なモデル
    これは開発の観点からは明らかに単純ですが、私の研究と私の直感から、これは設計時、コンパイル時、および場合によっては実行時の両方で、ひどく実行できるように思われます。

このような大規模なデータベースに対してEFを使用するためのベストプラクティスは何ですか?具体的には、この量のDBオブジェクトに対するモデルを設計するときに、どのような戦略を使用しますか?上記のオプションよりもうまく機能するとは思わないオプションはありますか?

また、これはNHibernateなどの他のORMの問題ですか?もしそうなら、彼らはEFよりも優れたソリューションを考え出しましたか?

52
RationalGeek

個人的には、かなり複雑だが小さいプロジェクト(〜300テーブル)で、すべてのエンティティに対して1つの巨大なスキーマを作成してみました。私たちは、非常に正規化されたデータベース(第5の形式の正規化(大まかに言って))を持ち、多くの「多対多」の関係と極端な参照整合性の強制が行われていました。

また、「リクエストごとの単一インスタンス」戦略も使用しましたが、これも私が助けたとは思いません。

シンプルで適度にフラットな「明示的に定義された」リスト、ルックアップ、および保存を行う場合、パフォーマンスは一般的に許容可能でした。しかし、私たちが深い関係を掘り始めたとき、パフォーマンスは大幅に低下したように見えました。このインスタンスのストアドプロシージャと比較すると、比較はありませんでした(もちろん)。パフォーマンスを向上させるために、コードベースをあちこちに微調整できたと思いますが、この場合、時間の制約のために分析せずにパフォーマンスを向上させるだけで済み、ストアドプロシージャにフォールバックしました(まだマッピングされています) EFは厳密に型指定された結果を提供するため、EFを介して)、いくつかの領域のフォールバックとしてのみ必要でした。コレクションを作成するために(.include()を無傷で使用して)データベース全体をトラバースする必要があった場合、パフォーマンスは著しく低下していましたが、要求しすぎていた可能性があります。

したがって、私の経験に基づいて、インテントごとに個別の.edmxを作成することをお勧めします。そのニーズの範囲に基づいて、使用するものだけを生成します。目的のタスク用にスコープが小さい.edmxファイルがいくつかあり、オブジェクトを構築するために複雑な関係をトラバースする必要がある大きいファイルがある場合があります。その魔法のスポットがどこにあるのかはわかりませんが、確かにあるのです...笑...

正直なところ、私たちがやってくるいくつかの落とし穴(複雑なトラバース)を除いて、巨大な.edmxは「動作」の観点からはうまく機能しました。しかし、明示的に無効にしないと、コンテキストが背後で行う「フィックスアップ」の魔法に注意する必要があります。データベースに変更が加えられたときに.edmxの同期を維持するだけでなく、サーフェス全体をワイプしてエンティティを再作成する方が簡単な場合があり、3分程度かかるため、たいしたことではありませんでした。

これはすべてEntityFramework 4.1でのことでした。私はあなたの最終的な選択と経験についても聞きたいです。

そして、あなたがnHibernateについての質問に関しては、それは私の意見ではワームの缶の質問です、あなたはフェンスの両側で吠えるでしょう...私は多くの人々がEFをバッシングする目的でEFをバッシングするのを聞いていますEF自体に固有のニュアンスに挑戦し、理解します。nHibernateを本番環境で使用したことはありませんが、一般に、マッピングなどを手動で明示的に作成する必要がある場合は、より限定的な制御が得られます。ドラッグアンドドロップ、生成、およびLINQを使用したCRUDとクエリの開始を行うことができます。

これがお役に立てば幸いです。

32
hanzolo

簡単な説明から始めましょう。私はそのような大規模なデータベースでの経験がないので、私の答えの残りは実世界の例に基づいていません。

したがって、BIGデータベースがあり、それをORM/EFで使用したいとします。私は2番目の選択で行きます。これが私の簡単な説明です:

  • マッピングにより複雑さが増します。現在のアプリケーション/プロジェクト/モジュールが必要としないエンティティに複雑さを追加する必要はありませんが、粒度を低くしすぎないでください。画面ごとに個別のマッピングセットを用意しても、効果はありません。
  • 作業単位を達成したい。ほとんどの場合、どのモジュールが必要とするかを指定できるはずです(すべての場合に必要というわけではありません)。これらのテーブルを単一のマッピングセットに入れると、単一のコンテキストインスタンスによる読み取りとデータ変更を処理できるようになります。これが最終的なターゲットです。
  • モデルが正確に何を意味するのかはわかりませんが、マッピングセットが異なっていても、同じエンティティタイプを使用してマッピングセット間でクラスを共有できます。したがって、2つのモジュールでUserテーブルを使用する場合、同じものを表すために2つのUserクラスは必要ありません。それでも単一のテーブルを使用でき、コードマッピング(別名コードファースト)の場合は、マッピングを1回定義して複数のマッピングセットにロードすることもできるため、DRY原則に違反しませんが、コード-firstアプローチでは、ビューとストアドプロシージャに関してより多くの制限があります。EDMXはこれを難しくします。クラスは再利用できますが、マッピングを再利用することは不可能です。
  • モジュール間クエリについてはどうですか?これらのクエリが発生する可能性がありますが、正直なところ、すべてがEFで処理される必要はありません。一般的なケースでEFを利用して通常のデータアクセスを簡略化できますが、5つの異なるモジュールに属するテーブルを結合する特別なクエリが必要な場合は、直接実行するか、ストアドプロシージャでラップすることができます。ネイティブデータアクセスを100%置き換えることは困難で、複雑で、生産性を低下させる可能性があります。
  • 最後のポイントは単に実用的です:VSツールがそのような大きなオブジェクトのセットで動作する準備ができているとは思いません-デザイナーではなく、インポートツールでも。 VS2008では、従来のデータアクセスとSQLデータベースプロジェクトを備えた非常に大規模なデータベースで作業していました。複雑なプロジェクトのユーザーエクスペリエンスは非常に悪かったです。使用するテーブルの数は少なく保つ必要があります。デザイナーの上限は100〜200の範囲にする必要がありますが、単一のコンテキスト(マッピングセット)で処理される100のテーブルでも、1つのクラスに対して責任が大きすぎるように聞こえます(100のセットプロパティがあるとします)。コンテキストで公開-それは良いデザインのようには見えません)。
13
Ladislav Mrnka

技術的な観点からこの種の質問を決めることはできないと思います。ユースケース(ユーザーストーリーなど)に基づいてアーキテクチャを構築することをお勧めします。まず、ビジネスオブジェクトを見つけます。エンティティオブジェクトは、デフォルトではビジネスオブジェクトではありません。通常、エンティティオブジェクトの前にビジネスオブジェクトがあります。その後、ユーザーの要件に基づいて、本当に必要なものを段階的に決定できます。

「優れたアーキテクトは、行われない決定の数を最大化します。」ロバート・C・マーティン

http://cleancoder.posterous.com/architecture-deference

4
ollins

私はハイブリッドアプローチを使用しています-OLTPものはEFによって処理されますが、バッチ挿入、一括更新、レポートクエリなどの重い操作はストアドプロシージャによって処理されます。これにより、移行パスも簡単になりますデータレイヤーの完全な再書き込みを一度に行わない場合。

3
Nik