web-dev-qa-db-ja.com

JPA継承@EntityGraphには、サブクラスのオプションの関連付けが含まれます

次のドメインモデルを前提として、Answersとそれぞれのサブ子を含むすべてのValuesを読み込み、それをAnswerDTOに入れてJSONに変換します。有効な解決策はありますが、アドホック@EntityGraphを使用して解消したいN + 1の問題があります。すべての関連付けは_​​LAZYで構成されます。

enter image description here

@Query("SELECT a FROM Answer a")
@EntityGraph(attributePaths = {"value"})
public List<Answer> findAll();

Repositoryメソッドでアドホック@EntityGraphを使用すると、Answer->ValueアソシエーションでN + 1が発生しないように値をプリフェッチできます。私の結果は問題ありませんが、selectedsのMCValue関連付けを遅延ロードするため、別のN + 1問題があります。

これを使う

@EntityGraph(attributePaths = {"value.selected"})

selectedフィールドは、もちろん一部のValueエンティティの一部にすぎないため、失敗します。

Unable to locate Attribute  with the the given name [selected] on this ManagedType [x.model.Value];

値がselectedの場合に、JPAがMCValue関連付けのみをフェッチしようとするようにするにはどうすればよいですか? optionalAttributePathsのようなものが必要です。

17
Stuck

コメントの後に編集:

申し訳ありませんが、最初のラウンドでは問題を理解していません。問題は、findAll()を呼び出そうとしたときだけでなく、spring-dataの起動時に発生します。

ですから、完全な例をナビゲートして、私のgithubからプルすることができます: https://github.com/bdzzaid/stackoverflow-Java/blob/master/jpa-hibernate/

このプロジェクト内で問題を簡単に再現して修正できます。

事実上、Springデータと休止状態は、デフォルトでは「選択された」グラフを決定することができず、選択されたオプションを収集する方法を指定する必要があります。

したがって、最初に、クラスのNamedEntityGraphsを宣言する必要がありますAnswer

ご覧のとおり、クラスの属性valueには2つのNamedEntityGraphがありますAnswer

  • 最初のすべてValue負荷との特定の関係なし

  • 特定のMultichoice値の2番目。これを削除すると、例外が再現されます。

2番目に、トランザクションコンテキストである必要がありますanswerRepository.findAll()タイプのデータをフェッチする場合[〜#〜] lazy [〜#〜]

@Entity
@Table(name = "answer")
@NamedEntityGraphs({
    @NamedEntityGraph(
            name = "graph.Answer", 
            attributeNodes = @NamedAttributeNode(value = "value")
    ),
    @NamedEntityGraph(
            name = "graph.AnswerMultichoice",
            attributeNodes = @NamedAttributeNode(value = "value"),
            subgraphs = {
                    @NamedSubgraph(
                            name = "graph.AnswerMultichoice.selected",
                            attributeNodes = {
                                    @NamedAttributeNode("selected")
                            }
                    )
            }
    )
}
)
public class Answer
{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private int id;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "value_id", referencedColumnName = "id")
    private Value value;
// ..
}
0
bdzzaid