同様のデータを取得するデータアクセスメソッドの重複を防ぐ方法は?


8

私がチームで取り組んでいるほぼすべてのプロジェクトで、同じ問題が侵入しているようです。誰かがデータを必要とするUIコードを書き、データアクセスメソッドを書きます。

AssetDto GetAssetById(int assetId)

1週間後、他の誰かがアプリケーションの別の部分で作業してAssetDtoいて、「承認者」を含む必要がありますが、次のように書きます:

AssetDto GetAssetWithApproversById(int assetId)

1か月後、誰かがアセットを必要としていますが、現在は「質問」(または「所有者」または「実行中のリクエスト」など)が含まれています。

AssetDto GetAssetWithQuestionsById(int assetId)
AssetDto GetAssetWithOwnersById(int assetId)
AssetDto GetAssetWithRunningRequestsById(int assetId)

そして、そのようなメソッドGetAssetWithOwnerAndQuestionsByIdが出現し始めると、さらに悪化します。

現れるパターンが表示されます。オブジェクトは大きなオブジェクトグラフにアタッチされており、このグラフのさまざまな部分をさまざまな場所に配置する必要があります。

もちろん、ほとんど同じことをするメソッドがたくさんあるのを防ぎたいです。それは単にチームの規律の問題ですか、それともこれを防ぐために使用できるパターンがありますか?場合によっては、個別のメソッドを使用することが理にかなっている可能性があります。つまり、実行中のリクエストでアセットを取得するのはコストがかかるため、常にこれらを含めたくありません。そのような場合の対処方法は?


1
アクセスが試行されたときに、プロパティの遅延読み込み(Hibernateを介したGorm)を処理するgrailsのようなものを使用できます。この方法では、呼び出しを行うだけで、a = getAssetById(x)a.questionsなどを呼び出すことができます。アクセスが試行されると、基礎となるORMシステムがそれをロードするため、それらを特にロードする必要はありません。
techfoobar 2012

1
それは可能ですが、クエリの実行中はデータベースコンテキストを開いたままにする必要があります。この種の知識がデータアクセス層から漏れることはありません。また、実行されるクエリに対する制御が弱くなります。しかし、非常に興味深いオプション...
ロナルドウィルデンベルク

ええ、それはDTOでそれを分離することの全体的なポイントだと思います。Grailsは...物事の非DTOの道を行く
techfoobar

単一のインターフェースからオープンエンドのクエリを実行するには、そのインターフェースがドメイン固有のクエリ言語である必要があります。受け入れられた答えはそれに似ています。
mike30 2012

回答:


4

構文的には、流動的なインターフェイスを備えた中間クエリ構築オブジェクトを作成します。

// all the basic, cheap to query fields
AssetDto a = AssetRetriever(asset_id).fetch() 

// some common expensive fields
AssetDto a = AssetRetriever(asset_id).withOwner().withQuestion().fetch() 

// numerous less common fields may not command dedicated methods
AssetDto a = AssetRetriever(asset_id).withFields("foo", "bar").fetch() 

// Better yet, use an enum and enjoy static checking
AssetDto a = AssetRetriever(asset_id).withFields(F_OWNER, F_QUESTION).fetch() 

実装するのに十分明白であることを願っています。実際にデータベースにアクセスする唯一の方法はfetch()です。


私はこのソリューションが本当に好きです。それは私が包括的でクリーンな構文で達成したいことを強制し、インターフェースの拡張とSQLクエリの最適化に多くの可能性を与えます。
Ronald Wildenberg 2012

2

大きなオブジェクトを扱う場合、これは非常に一般的です。新しいメソッドを追加するとパフォーマンスが向上しますが、保守性が大幅に低下します。また、これら2つの中から選択する必要があります。

一般的に使用されるデータ(必ずしも最小ではない)を返すメソッド、オブジェクト全体を返すメソッド、そして最も高価なリソースの場合はさらにいくつかのメソッドがあることをお勧めします。

別のアプローチは、AssetQuestions GetAssetQuestionsById(int assetId)またはのように、オブジェクトの必要なフィールドのみを返すメソッドを持つこと Owners GetAssetOwnersById(int assetId)です。

これに加えて、データの取得に関するいくつかのルールを確立する必要があります。たとえば、誰かがオブジェクトの5つのフィールドを必要とし、8を返す既存のメソッドがある場合、既存のメソッドを使用する必要があります。


問題が発生しないように強制できるパターンがあるといいのですが、あなたの解決策が最善だと思います。新しいデータアクセスコードを書くとき、それはより多くの規律と研究に帰着します。
ロナルドウィルデンベルク

関連するオブジェクトを取得するための追加のメソッドを導入するソリューションが気に入っています。データベースにデータを結合しなくなったため、少しパフォーマンスが低下する可能性がありますが、メンテナンス性のためにはおそらく大きな改善です。
ロナルドウィルデンベルク

3
私の頭に浮かぶ1つの「クレイジーな」ソリューションがあります。各パラメーターにブールフィールドを使用して型を作成し、取得するフィールドにtrueを設定し、そのオブジェクトをパラメーターとして渡します)))
superM

それも私の心を通り、唯一の欠点は、データアクセスコードで考えられるすべての組み合わせを考慮する準備が必要なことです。もちろん、最も一般的なケースに対して非常に効率的なクエリを作成することはできますが
Ronald Wildenberg '27

それも維持するのは難しいと思いますが、場合によってはうまくいくかもしれません
superM

1

私は最近この同じ問題を経験し、次の解決策を採用しました:

データアクセスメソッドは、単一のリソース(データベーステーブルなど)からのみデータを取得する必要があり、プロセスがメインオブジェクトに追加された関連オブジェクトを必要とする場合、それぞれのオブジェクトを担当するメソッドを呼び出す必要があります。

このように、承認者のいるアセットが必要な場合は、オブジェクトを結合するファサードメソッドを作成する必要があります。

例:

public Class AssetFacade {

   public AssetDto getAssetWithQuestionsByAssetId(int assetId) { 

      AssetDto asset = AssetDao.getAssetById(assetId);
      List<QuestionDto> questions = AssetDao.getQuestionsByAssetId(assetId);
      asset.setQuestions(questions);

      return asset;
   };
 }

1
これは可能な解決策ですが、データベースを介したデータアクセスを最適化するためのすべての可能性を失うことは望ましくありません。つまり、3つのテーブルを結合する1つのクエリは、3つの個別のクエリよりも高速になる場合があります。
Ronald Wildenberg 2012

あなたと同意しますが、その時より良い解決策を見つけることができませんでした。私がより良い方法を学ぶためにこの質問を作成してくれてありがとう!
marcioggs 2012

0

それは単にチームの規律の問題ですか、それともこれを防ぐために使用できるパターンがありますか?

はい、それはチームの命名パターンにおけるいくつかのガイドラインの問題です。GetEntityById()、GetAllEntities()、SetEntity()、DeleteEntityById()などのシンプルな4つのメソッドを設定できます。

さらに、名前が付いた2つのAssetSimpleDto GetAssetById(assetId)dtoとと呼ばれる別の詳細なdto がある場合がありますAssetDto GetAssetDetailById(assetId)。最初の方法とdtoは最小限に抑えるようにカスタマイズされていますが、2番目の方法は、機能に必要なすべての関連情報を提供します。


残念ながら、このケースは「単純化する」または「すべてを取得する」ほど簡単ではないため、根本的な問題を実際に解決することはできません。'get simple'によって返されないオブジェクトグラフの一部が必要なため、これによりおそらくすべての人が 'get all'メソッドを使用するようになります。
Ronald Wildenberg 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.