ドミトリーSenkovich:
私はJPAの基準APIにHibernateの基準APIを使用してから私たちのDAOを移行しています。私はいくつかのクラスを持っている@ManyToOne
が:
@Entity
@Table(name = "A_TABLE", schema="SCHEMA_NAME")
public class A {
@ManyToOne
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b1;
@ManyToOne
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b2;
...
}
@Entity
@Table(name = "B_TABLE", schema="SCHEMA_NAME")
public class B {
}
クエリで私が使用しているJoinType.LEFT
デフォルトで生成さを取り除くために、CROSS JOIN
さん:
if (LEFT_OUTER_JOIN_ENTITIES.contains(field)) {
path = ((From) path).join(field, JoinType.LEFT);
} else {
path = path.get(field);
}
私は右の結果を得ている、すべてA
とB
レコードが正しく取得されます。ただし、移行後に私は、n + 1問題を取得しています:すべてB
のレコードが使用しているにもかかわらず1対1を取得しているLEFT OUTER JOIN
「が生成クエリでね。(Hibernateの基準APIを使用する場合)以前にHibernateは、N + 1は、同じ生成されたSQLに参加せずにクエリを満たすことができました。
任意のアイデアや助けをありがとう!
UPDATEの使用例として、if-else
「b1.fieldName」で検索のための上記の私は、次のようになるだろう。
criteriaBuilder.equal(root.join("b1", JoinType.LEFT).get("someFiled"), 42)
ヴラッド・ミホールセア:
N + 1問題がから来ているデフォルトEAGERフェッチ戦略の@ManyToOne
団体。
だから、あなたはに切り替える必要がありFetchType.LAZY
、このように、:
@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '1' OR B.B_CODE = '2') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b1;
@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT * FROM (SELECT B.B_ID FROM SCHEMA_NAME.B_TABLE B WHERE B.A_ID = B_ID AND (B.B_CODE = '3' OR B.B_CODE = '4') ORDER BY B.B_CREATED_TIMESTAMP DESC) WHERE ROWNUM = 1)")
private B b2;
あなたは自動的にあなたのアプリケーションの他の部分に影響を与える可能性があることを自動的N + 1問題を検出したい場合は、チェックアウトこの記事を。
あなたが基準APIとの関連を即時にフェッチする必要がある場合は、使用する必要がありますfetch
代わりにjoin
。
if (LEFT_OUTER_JOIN_ENTITIES.contains(field)) {
path = ((From) path).fetch(field, JoinType.LEFT);
} else {
path = path.get(field);
}