ORMはリッチドメインモデルの作成を可能にしますか?


21

私のほとんどのプロジェクトでHibernateを約8年間使用した後、私はその使用を思いとどまらせ、ストアドプロシージャを介してのみDBと対話するアプリケーションを求めている会社に行きました。

数週間これを行った後、私が構築し始めているアプリケーションのリッチドメインモデルを作成することができず、アプリケーションは(恐ろしい)トランザクションスクリプトのように見えます。

私が発見した問題のいくつかは次のとおりです。

  • ストアドプロシージャは最小量のデータを読み込むだけなので、オブジェクトグラフをナビゲートすることはできません。つまり、フィールドが異なる類似したオブジェクトがある場合があります。たとえば、顧客からすべてのデータを取得するストアドプロシージャと、顧客からアカウント情報といくつかのフィールドを取得するストアドプロシージャがあります。
  • 多くのロジックは最終的にヘルパークラスになるため、コードはより構造化されます(エンティティは古いC構造体として使用されます)。
  • ストアドプロシージャから結果セットを抽出し、エンティティに配置するフレームワークがないため、より退屈な足場コード。

私の質問は:

  • 誰もが同様の状況にあり、ストアプロシージャアプローチに同意しませんでしたか?あなたは何をした?
  • ストアドプロシージャを使用する実際の利点はありますか?「誰もドロップテーブルを発行できない」という愚かな点は別として。
  • ストアドプロシージャを使用してリッチドメインを作成する方法はありますか?オブジェクトグラフをナビゲートできるように、AOPを使用してエンティティにDAO /リポジトリを挿入する可能性があることを知っています。ブードゥー教に非常に近いので、このオプションは好きではありません。

結論

まず、答えてくれてありがとう。私が到着した結論は、ORMは(一部の人が述べたように)リッチドメインモデルの作成を有効にしないが、(多くの場合繰り返し)作業の量を単純化するということです。以下は結論のより詳細な説明ですが、ハードデータに基づいていません。

ほとんどのアプリケーションは、情報を要求して他のシステムに送信します。これを行うには、モデル用語で抽象化(ビジネスイベントなど)を作成し、ドメインモデルがイベントを送受信します。通常、イベントにはモデルからの情報の小さなサブセットが必要ですが、モデル全体ではありません。たとえば、オンラインショップでは、支払いゲートウェイはユーザーに請求するためにユーザー情報と合計を要求しますが、購入履歴、利用可能な製品、およびすべての顧客ベースは必要としません。そのため、イベントには小規模で特定のデータセットがあります。

アプリケーションのデータベースを外部システムとして使用する場合は、ドメインモデルエンティティをデータベースにマッピングできる抽象化を作成する必要があります(NimChimpskyが言及したように、データマッパーを使用)。明らかな違いは、各モデルエンティティのデータベース(レガシースキーマまたはストアドプロシージャ)へのマッピングを手作業で作成する必要があることです。2つは同期していないため、1つのドメインエンティティが部分的にマッピングされる可能性がありますデータベースエンティティ(たとえば、ユーザー名とパスワードのみを含むUserCredentialsクラスが他の列を持つUsersテーブルにマップされる)、または1つのドメインモデルエンティティが複数のデータベースエンティティにマップされる場合があります(たとえば、1対1の場合テーブルに1つのマッピングがありますが、1つのクラスにすべてのデータが必要です)。

エンティティが少数のアプリケーションでは、エンティティを横断する必要がない場合、追加の作業量は少ないかもしれませんが、エンティティを横断する条件付きの必要がある場合は増加します(したがって、ある種の「怠lazな」読み込み」)。アプリケーションが成長してより多くのエンティティを持つようになると、この作業は増加するだけです(そして、非線形に増加すると感じています)。ここでの私の仮定は、ORMを再発明しようとしないことです。

DBを外部システムとして扱うことの利点の1つは、アプリケーションの2つの異なるバージョンを実行し、各アプリケーションのマッピングが異なる状況を回避できることです。これは、本番環境への継続的な配信のシナリオでより興味深いものになります...しかし、これは、ORMでもそれほどではないかもしれません。

開発者は、データベースにアクセスできなくても、悪意のあるコードを挿入するだけで、システムに格納されている情報のほとんどではなくてもほとんどを取得できることに基づいて、セキュリティの側面を無視します。親愛なる主よ、顧客のクレジットカードの詳細を記録する行を削除するのを忘れたとは信じられません!)。


小さな更新(6/6/2012)

ストアドプロシージャ(少なくともOracleの場合)では、テーブルの構造を変更するとプロシージャとトリガーが無効になるため、ダウンタイムがゼロの連続配信のようなことはできません。したがって、DBが更新されている間、アプリケーションもダウンします。Oracleは、このためのEdition-Based Redefinitionと呼ばれるソリューションを提供しますが、この機能について私が尋ねた少数のDBAは、実装が不十分であり、運用DBに配置しないと述べました。


当然、Hibernate 行うことを実行し、動的プロキシオブジェクトを生成するために継承を使用することができます。これにより、オブジェクトグラフを取得できます。D:それはしかし、SPで非常にハックです
マックス

そのため、10年以上の休止状態チームの経験なしに、休止状態の半分を再調査することになります:)。
オーガスト

1
DBAは、特定のユーザーによる特定のテーブルの削除を防止する必要があります。どのようにそれを試みるかは問題ではありません。
-JeffO

1
あなたは見てかかることがありますMyBatisのを -それはあなたが必要とする機能を提供するかもしれません。これは、マッピングフレームワークよりもORMではありません。好きなようにSQLを記述し、Mybatisにオブジェクトモデルのどこに配置するかを伝えることができます。複数のクエリで大きなオブジェクトグラフを処理します。これは、状況(多くのシンストアドプロシージャ)のように聞こえます。
マイケルK

1
@Augusto:SPの使用によるものではなく、オブジェクトの関係をサポートしていない独自のマッピングフレームワークの使用が原因で、同様の状況にあります。適切なORMを使用して数分で記述できるコードを書くのに何日も費やしました。私はその問題を解決できませんでした。
ケビンクライン

回答:


16

アプリケーションは、ドメイン主導の設計原則から引き続きモデル化する必要があります。ORMを使用するか、ストレートJDBCを使用するか、SP(または何でも)を呼び出すかは問題ではありません。この場合、モデルをSPから抽象化する薄層がうまくいくことを願っています。別のポスターが述べ、あなたはサービスとしてのSPとその結果を表示し、あなたのドメインモデルに結果をマップする必要があります。


Martijn、DDDの原則を使用してアプリをモデル化する必要があることに同意しますが、私が直面している問題(および解決策がある場合は教えてください!!)は、一部のストアドプロシージャがDDDエンティティをインスタンス化するためにほとんど情報を返さないことです。ストアドプロシージャが返す情報についてもう少し説明したこのコメントを参照しください。これを回避するには、複数のストアドプロシージャを呼び出し、たとえばすべてのユーザーの詳細を取得してから、別のユーザーの詳細を呼び出してすべてのアカウント情報を取得しますが、間違っているように感じます:)。
アウグスト

1
@Augustoうーん...あなたはアプリ開発者です。そのため、特定のフィールドがNULLに設定された特定のオブジェクトが存在することが理にかなっているかどうかを判断する必要があります。理にかなっている場合(たとえば、特定のタスク)、それをさせてください。そうでない場合は、SPの作成者にさらにデータを提供してもらい、オブジェクトを作成できるようにします。
ヤチェクプルシア

そして、Jacekのコメントに加えて、実際に2つ以上のストアドプロシージャを呼び出すことは完全に受け入れられます。ドメインモデルを作成するために呼び出す必要がある2つのリモートサービスと考えてください。
マルタインVerburg

@Martijn:私の経験では、薄い層では十分ではありません。マッピングコードは、基になるビジネスロジックよりもかなり長い場合があります。
ケビンクライン

@ケビン・クライン-良い点、答えに「願わくば」を入れました:
Martijn Verburg

5

ストアドプロシージャを使用する実際の利点はありますか?

金融の世界(およびSarbanes-Oxley準拠が必要な場所)では、システムを監査して、システムが本来行うことを確実に実行できるようにする必要があります。これらの場合、すべてのデータアクセスがストアドプロシージャを介している場合、コンプライアンスを確保するのがはるかに簡単です。そして、アドホックSQLがすべて削除されると、物事を隠すのがはるかに難しくなります。これが「良いこと」になる理由の例については、ケントンプソンの古典的な論文Reflections on Trusting Trustを参照してください。


はい100万回はい!また、ユーザーがテーブルに対して直接的な権限を持たないことや、ストアドプロシージャが非常に役立つことを含め、ユーザーが行うべきでない任意の操作を実行できないことを確認する必要があります。
HLGEM

1
私は公開会社で働いており、SOXに対応しています。私の監査の知識が乏しいかもしれませんが、DBレベル(ストアドプロシージャ経由)での監査とアプリケーションレベルでの監査の違いはわかりません。各アプリケーションには独自のDBスキーマが必要であり、そのスキーマは異なるアプリケーション間で共有されるのではなく、アプリケーションからのみアクセスできます。
アウグスト

リンク切れ...
アレックスR

@AlexR、固定リンク
タングレナ

2

ストアドプロシージャは、クライアント側のSQLコードよりもはるかに効率的です。DBでSQLをプリコンパイルし、最適化を実行できるようにします。

アーキテクチャ的には、SPはタスクに必要な最小限のデータを返します。これは、転送されるデータが少ないことを意味します。このようなアーキテクチャを持っている場合、DBをサービスと考える必要があります(Webサービスと考え、各SPは呼び出すメソッドです)。このように操作することは問題ではありませんが、ORMはリモートデータをローカルであるかのように操作するためのガイドであり、注意しないとパフォーマンスの問題を引き起こすように仕向けます。

私は、SPを完全に使用し、DBがデータAPIを提供し、それを使用した状況にありました。その特定のアプリは非常に大規模で、驚くほどうまく機能しました。その後、SPについて悪いことを言うことはありません!

もう1つの利点があります-DBAがすべてのSQLクエリを作成し、DB内のすべてのリレーショナル階層を喜んで処理するため、必要はありません。


3
gbjbaanb、あなたが言ったことのほとんどは古いデータベースに当てはまります。ほとんどの新しいデータベースは、クエリを頻繁に再コンパイルして、どの新しい最適化を使用するかを決定します(保存されている場合でも)。DBを外部システムとして使用することについてあなたが言ったことに同意しますが、アプリケーションがデータベースを所有し、両方が可能な限り同期している必要があるため、多くの作業としても見ています。たとえば、テーブル/クラスおよびフィールド/列の命名。また、DBAに手順を記述させるアプローチは、学際的なチームを持つというよりも、開発サイロのような匂いがします。
アウグスト

7
SPは必ずしもより効率的であるとは限りません。SQLをDBAに引き渡すことは悪い方法だと思います。ドメインの専門家として、開発者は、彼らが取得するデータを知っている必要があり、どのようにそれを得るために
マルタインVerburg

1
これは良い答えですが、私の経験では、ほとんどのクライアントは、ストアドプロシージャを介したデータアクセスの制御のパフォーマンス向上と、アプリケーション層でORMツールを最大限に活用する不便さを実際に必要としません。これらのアーキテクチャ上の決定は、他のスキルを持たない「灰色のひげ」ストアドプロシージャプログラマの肥大化した給与を正当化する必要があるソフトウェアショップで行われます。
maple_shaft

1
@Augusto the approach of letting the DBAs write the procedures smells like development silos+100のインターネットで、この真実の宝石をお届けします。これは常に、データアクセスがストアドプロシージャによって制御されている場合と考えてきました。
maple_shaft

1
@maple_shaft:なぜ、SPを作成するDBAは開発者チームの一部と見なされないのですか?それが機能する場合、彼らはシステムのこの側面を非常によく知っている専門のコーダーであり、ほとんどの汎用開発者よりもはるかに優れています。これが、ORMの人気を高めている問題かもしれません。つまり、GUIを設計者に任せることを誰も二度と考えないのに、なぜスキーマを行うデータアーキテクトが嫌いなのでしょうか。
gbjbaanb

2

多くの場合、開発者はドメインモデルとしてORMオブジェクトを誤って使用します。

これは誤りであり、ドメインをDBスキーマに直接結び付けます。

本当に必要なのは、必要に応じて豊富な別のドメインモデルであり、ORMレイヤーを個別に使用することです。

これは、オブジェクトの各セット間のマッピングが必要であることを意味します。


1
これは良い考えですが、小規模なプロジェクトでは本当にやり過ぎのように感じ始めます。このアプローチでは、ORM永続層とドメインモデルの間に変換層も必要です。
maple_shaft

@maple_shaftが同意し、それが私が「マッピング」と言ったものです:-)
ozz

@Ozz、私が取り組んできた方法は、まさにエンティティクラスがドメインモデルであるということです(そして、かなりの成功を収めることができます)。ドメインモデルをスキーマに結び付けることに同意しますが、構成よりも規約を使用しているので、まさにそれが私が望んでいることです。その情報が保存されているテーブルと列の名前について。
アウグスト

@Augusto私もやった!maple_shaftが言っているように、小さなCRUDスタイルのアプリには問題ありませんが、OPが発見している多くの問題があります。1つの例として、多対多のマッピングテーブルがある場合があります。たとえば、StudentClassesは、学生をクラスにマッピングし、StudentIDとclassIDのみを含むため、必ずしもドメインにマッピングする必要はありません。これは、私の頭の例の一番上からの簡単な例です。
オズ

2
@Ozz:あなたのコメントはORMのアイデアそのものと矛盾しているようです。ORMは「ドメインをDBスキーマに直接結び付けません」。ORM は、個別のDAOレイヤーを必要とせずに、ドメインをDBスキーマにマップします。これがORMの重要なポイントです。そして、ほとんどのORMは、マッピングテーブルにドメインモデルを必要とせずに、多対多のマッピングをうまく処理します。
ケビンクライン

1

Hibernateを使用する必要はありませんが、ドメインオブジェクトはどのように入力してもかまいません。適切な用語はdata-mapperです。永続化されたデータは、ドメインオブジェクトとはまったく異なる構造になる可能性が非常に高くなります。


現在、データマッパーを使用していますが、問題は、ストアドプロシージャが最小限のデータセットを返すことです。これは、オブジェクトを満たすのに十分でない場合があります(ストアドプロシージャがより多くの情報を返すことを許可する必要がある場合があります)。たとえば、1つのストアプロシージャがユーザーの電子メール、前名、姓を返す場合があります。もう1つは、ユーザーIDとアドレスを追加します。データが異なるため、データを保存するために異なるオブジェクトを使用しています。つまり、異なる「ユーザー」クラスがあります。ここでは継承の使用を避けようとしていますが、それは間違った使い方だと思うからです。
アウグスト

@Augusto:インターフェース?
Kramii回復モニカ

@Karmii、ここではインターフェースが役に立たないと思います。異なるクラスでロジックを複製する必要があるからです。それともインタフェースを使用して、ヘルパークラスに処理を委譲するが、それはOO本当にありませんでした:(。
アウグスト

1
私は問題を理解していない@Augusto:あなたはSPROCを変更するか、別のものを作成し、マッピングを行うマッパデータを聞かせので、「保存されprocsのは、時々 、オブジェクトを満たすのに十分ではありませんデータの最小セットを返します」
ニムチンプスキー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.