0

EDIT(完全に再構築されたアプローチ):

新しいプロジェクトで JPA の使用を促進しようとしていますが、おそらく些細な問題に苦しんでいます: 2 つのテーブル (親と子) 間の INNER JOIN です。

重要な情報のみを提供し、残りはすべて省略します。必要な場合は、お気軽にお問い合わせください。LANGUAGE と MESSAGE_RESOURCE の 2 つのテーブルがあり、親テーブルは LANGUAGE (主キー ID_LANGUAGE) であり、子テーブルには、同じく ID_LANGUAGE という名前の親テーブルへの外部キーがあります。

Language (親) クラス:

@Entity
@Table(name = "PF_LANGUAGE")
public class Language {
    @Id
    @Column(name = "ID_LANGUAGE", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int idLanguage;

    @OneToMany(mappedBy="language",targetEntity=MessageResource.class, fetch=FetchType.EAGER)
    private Collection<MessageResource> messageResources;
}

子クラス:

@Entity
@Table(name = "PF_MESSAGE_RESOURCE")
public class MessageResource {

    @Id
    @Column(name = "ID_MESSAGE_RESOURCE", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int idMessageResource;

    @ManyToOne(optional=false)
    @JoinColumn(name="ID_LANGUAGE")
    private Language language;
}

名前付きクエリを使用して結果を取得しています。

entityManager.createNamedQuery("select l, r from Language l join l.messageResources r");

これにより、各エントリに言語と MessageResource のペアが 1 つ含まれるオブジェクト配列が結果として得られます。問題は、これが別々のクエリで行われていることです。

デバッグ出力で、最初のクエリが両方のテーブル間の INNER JOIN であり、出力に両方のテーブルの列が含まれていることがわかります。これで十分です。しかし、JPA は 2 つの追加クエリ (LANGUAGE レコードの数) を実行して、各親テーブルの子テーブル値を再度フェッチしますが、これは必要ありません。

すべてのデータを取得するのに十分な最初のクエリ:

select
   language0_.ID_LANGUAGE as ID1_5_0_,
   messageres1_.ID_MESSAGE_RESOURCE as ID1_4_1_,
   language0_.CODE as CODE5_0_,
   language0_.DATE_INS  as DATE3_5_0_,
   language0_.DESCRIPTION  as DESCRIPT4_5_0_,
   messageres1_.DATE_INS  as DATE2_4_1_,
   messageres1_.KEY as KEY4_1_,
   messageres1_.ID_LANGUAGE as ID5_4_1_,
   messageres1_.VALUE as VALUE4_1_ 
from
   PF_LANGUAGE language0_ 
inner join
   PF_MESSAGE_RESOURCE messageres1_ 
on language0_.ID_LANGUAGE=messageres1_.ID_LANGUAGE

次のような 2 つの冗長クエリも、最初の内部結合の後にデータベースに対して実行されます (LANGUAGE テーブル レコードごとに 1 回実行されます)。

select
    messageres0_.ID_LANGUAGE as ID5_5_1_,
    messageres0_.ID_MESSAGE_RESOURCE as ID1_1_,
    messageres0_.ID_MESSAGE_RESOURCE as ID1_4_0_,
    messageres0_.DATE_INS  as DATE2_4_0_,
    messageres0_.KEY as KEY4_0_,
    messageres0_.ID_LANGUAGE as ID5_4_0_,
    messageres0_.VALUE as VALUE4_0_ 
from
    PF_MESSAGE_RESOURCE messageres0_ 
where
    messageres0_.ID_LANGUAGE=?

JPA によって生成された 2 つの冗長な追加クエリを削除する必要があります。すべてのデータを取得するには、最初の内部結合で十分です。

これについては助けが必要です。手がかりはありますか?

4

4 に答える 4

1

それが実際の解決策であるかどうかはわかりませんが、熱心なフェッチに関する私の経験は悪いです。私が期待していないことは常に何らかの方法でフェッチされます。

あなたのクエリは奇妙です.LanguageとMessageResourceの両方を選択していることは意味がありません.

試してみてください:

fetch=FetchType.EAGERLanguage と MessageResource の関係を削除し、クエリを何かに変更します

select l from Language l join fetch l.messageResources where ....

言語と、そのインスタンスの集約されたメッセージ リソースをすべて 1 つの SQL で提供する必要があります。

トピック外の何か、なぜ MessageResource.language を持っているのだろうかinsertable=false, updatable=false。言語のように矛盾しているように見えます。このフィールドによってマッピングされた関係を指定しましたが、現在は挿入不可/更新可能にしています。

于 2012-09-18T03:50:36.017 に答える
1

fetch=FetchType.EAGERmessageResources を に変更してみてください。fetch=FetchType.LAZY 明示的に参加しているため、 に変更FetchTypeするとLAZY役立つ場合があります。

于 2012-09-19T07:44:02.587 に答える
0

標準アノテーションを使用して内部クエリの生成を強制する標準的な方法はないようです (JPA は標準であり、Hibernate、TopLink、Open JPA などの実装プロバイダーを使用しています)。異なる JPA 実装では、異なる結合戦略が使用されます。詳細については、こちらこちらをご覧ください。

于 2012-09-17T19:48:45.830 に答える
0

I don't quite understand why do you expect inner join in this case.

optional = "false" at @ManyToOne means that every MessageResource must have a Language, but it does not imply that every Language must have at least one MessageResource, therefore left join when loading Language is correct in this case - Language that you load may have no MessageResources associated with it.

EDIT: The purpose of find() is to load an object with the given id if it exists in the database. If you want something semantically different (for example, to load all Languages that have at least one MessageResource), you need to write a query for it, such as select l from Language l join l.messageResources.

于 2012-09-17T19:08:52.053 に答える