9

WebアプリケーションにJava+Springフレームワークを使用しています。ORMツールを使用していません。代わりに、単純なDAO/DTOパターンを使用してdbリレーションをJavaオブジェクトとしてモデル化しようとしています。DTOがデータベース内の単一のテーブルに正確に対応する場合は常に、非常に簡単です。しかし、外部キーを使用して他のテーブルを参照するテーブルがある場合、これに対する最善のアプローチはわかりません。Stackoverflowで同様の回答を探しましたが、私のニーズに合ったものを見つけることができませんでした。非常に具体的な例を挙げたいと思います。UserとGroupの2つのエンティティがあるとします。ユーザーDTOとグループDTOがあり、それぞれにUserDao(JdbcUserDao)とGroupDao(JdbcGroupDao)があります。

これで、ユーザーとグループを接続するDB内の関係ができました。1人のユーザーが複数のグループに属することができます。テーブル名はUser_Group_Associationで、次のDB定義があります。

user_id | group_id

ここで、user_idは、ユーザーテーブルを参照する外部キーです。同様に、group_idはグループテーブルを参照します。このDTOをJavaでモデル化する場合、次のようなことを行う必要があります。

public class UserGroupAssoc {
    private int userId;
    private int groupId;

    //Setters and getters follow
}

または、次のようになります。

public class UserGroupAssoc {
    private User user;
    private Group group;

    //Setters and getters follow
}

特定のUIのユースケース:ユーザー名とそれに属するグループ名を表示したい。このようなもの-

名前->グループ名

Keshav-> Admin、EndUser、ReportAdmin Kiran-
> ReportAdmin
Pranav-> EndUser

DTO設計への最初のアプローチでは、ユーザーの詳細(名前)とグループの詳細(名前)をDBから再度取得する必要があります。2番目のアプローチでは、UserGroupAssocオブジェクト自体を作成するときに、UserオブジェクトとGroupオブジェクトをフェッチする必要があります。

おそらく3番目のアプローチでは、UserGroupAssocDTOを次のように設計できます。

public class UserGroupAssoc {
    private String userName;
    private String groupName;
    private int userId;
    private int groupId;

    //Setters and getters follow
}

この3番目のアプローチでは、SQLでテーブルを結合して、ユースケースに必要なフィールドのみを取得し、それに応じてDTOをモデル化します。

このシナリオを達成するための標準的なアプローチはどれですか?DTO設計でテーブルを結合しても大丈夫ですか?1つのDTOは1つのテーブルのみに対応し、関連するオブジェクトはアプリレイヤーに集約する必要があるという意見もあります。これには、DBから複数のオブジェクトフェッチを実行するオーバーヘッドがありますか?正しいアプローチについて混乱しすぎて、長い説明をしてすみません!

4

1 に答える 1

6

免責事項: 私は ORM の専門家ではありません...

... しかし、古典的な多対多の関係では、3 番目のデータ モデル ( ) は必要ありませんUserGroupAssocUserクラスには次のコレクションが含まれGroupます。

public class User {
   // ... user fields ...
   List<Group> groups;
   // ... getters/setters ...
}

逆の関係 (グループにユーザーが含まれる) も必要な場合、Groupクラスは次のようになります。

public class Group {
   // ... group fields ...
   List<User> users;
   // ... getters/setters ...
}

繰り返しますが、これを行う古典的な方法は、コレクション内で「ドメイン オブジェクト」(DTO) を使用することです ( UserandGroupの代わりにuserIdandを使用しますgroupId)。

通常、3 番目のドメイン オブジェクトが必要になるのは、関連付けテーブル ( ) におよび(ユーザーをグループに追加できるようにする何らかの認証コードなどUser_Group_Association) 以外のものが含まれている場合のみです。user_idgroup_id

user_id | group_id | auth_code

この場合、UserGroupAssocクラスは次の構造を持つ可能性があります。

public class UserGroupAssoc {
    private User user;
    private Group group;
    private String authorizationCode;

    // ... setters/getters ...
}

そして、 と の間の多対多の関係は、この新しいドメイン オブジェクトとの 2 つの多対 1 の関係に変換されますUserGroup通常、ドメイン オブジェクトを使用することをお勧めします ( UserandGroupの代わりにuserIdandを使用しますgroupId)。

このシナリオを達成するための標準的なアプローチはどれですか?

ORM フレームワークを使用していた場合、それはフレームワークの標準的な方法でした。しかし、カスタム ORM ソリューションがあるため、それを言うのは困難です。

DTO 設計でテーブルを結合しても問題ありませんか?

データベース内のテーブルを結合することによって、アプリケーション層の DTO 設計が影響を受けるのはなぜですか? これは、オブジェクトとリレーショナルのインピーダンスの不一致のケースであり、1:1 の対応を維持しながらリレーショナル ドメインをオブジェクト ドメインに完全に抽象化することはできないため、漏れやすい抽象化の法則の可能性もあります。

1 つの DTO は 1 つのテーブルのみに対応し、関連するオブジェクトはアプリ レイヤーに集約する必要があるという意見もあります。それには、DB から複数のオブジェクトを取得するオーバーヘッドがありますよね?

ORM にはいくつかの制限があり (遭遇する可能性のあるいくつかの問題については、オブジェクトとリレーショナルのインピーダンスの不一致を再度参照してください)、リレーショナル データベースの制約に対応するためにドメイン オブジェクトをモデル化すること、またはその逆を行うことは困難です。レポートは、この方向の良い例です。

レポートは通常、複数のテーブルからデータを集計します。もちろん、これは一部の SQL 結合では問題ありませんが、結果をどのように DTO にマップするのでしょうか? ご本人様のおっしゃる通り…

DTO がデータベース内の単一のテーブルに正確に対応する場合はいつでも、非常に簡単です。

...しかし、レポート結果は単一のテーブルにマップされず、より多くのテーブルのフラグメントにマップする必要があります。

アプリケーションでのニーズによっては、奇妙なクラスやぎこちない SQL が作成される可能性があります。適切なオブジェクト モデルとそれらの間の関連付けを取得するために、必要以上のクエリを実行することになる場合があります。または、データベースへのトリップ数を制限してパフォーマンスを向上させるためだけに、より類似した DTO を使用することもできます。

つまり、私が言おうとしているのは (私は ORM の専門家ではないという免責事項です)、すべてのアプリケーションが ORM に適しているわけではないということです。ただし、それを進めることを検討している場合は、Hibernate/JPA が問題にどのように対処しているかを調べたり、代わりにそれらを使用したりすることもできます。

于 2012-01-08T11:41:31.353 に答える