なぜ、N + 1問題原因JPAで「新しい選択」を使用してPOJOクラスのエンティティを置くのですか?

ゼリー:

私は、次のエンティティを持っています:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "simple_entity")
public class SimpleEntity {

    @Id
    private Long id;

    @Column(name = "text")
    private String text;

}

私はいくつか取得したい追加の列を持つエンティティをデータベースから。これを行うには、私はシンプルなペアクラスを作成しました。

@Getter
@Setter
@AllArgsConstructor
public class Pair<First, Second> {

    private First first;
    private Second second;

}

それから私は、期待される結果を作成しJPQLでクエリを作成しました。

@Repository
public interface SimpleEntityRepository extends JpaRepository<SimpleEntity, Long> {

    @Query("SELECT new com.example.demo.Pair(m, false) FROM SimpleEntity m")
    List<Pair<SimpleEntity, Boolean>> getRecords();

}

クエリは、正しい結果を返しますが、追加のクエリに問題があります。

WTF

そのため、私はいくつかの質問を持っています:

  1. なぜ、JPAはこのように動作しますか?
  2. JPQL内の1つのクエリで、このデータを取得する方法はありますか?
  3. どのように私は(私が返すオブジェクトの溶液を見てきました[]が、それは素敵に見えない)いくつかの追加のデータと一緒にエンティティを取得する必要がありますか?
Lesiak:

ない完全な答えが、私はそれが議論にいくつかの情報が追加されますと信じて:

変圧器の結果

あなたは休止状態としてあなたの質問をマークとして、あなたは、Hibernate結果変圧器を使用することができます(5.2では非推奨としますが、6.0はアルファのままです):

List<Pair<SimpleEntity, Boolean>> resultList = entityManager.createQuery(
"select m as first, false as second from SimpleEntity m")
        .unwrap(org.hibernate.query.Query.class)
        .setResultTransformer(Transformers.aliasToBean(Pair.class))
        .getResultList();

これは想定していPair引数なしのコンストラクタを持っており、生成します。

select
    simpleenti0_.id as col_0_0_,
    0 as col_1_0_,
    simpleenti0_.id as id1_18_,
    simpleenti0_.text as text2_18_ 
from
    simple_entity simpleenti0_

適切なDTO

フィールドのリストを経由して構築することができ、クラス全体ではなく、エンティティを使用してください。あなたが選択したフィールドのリストを指定すると、クエリがうまく動作します、全体ではなく実体

public class SimpleEntityDTO {

    private Long id;
    private String text;
    private Boolean second;

    public SimpleEntityDTO() {
    }

    public SimpleEntityDTO(Long id, String text, Boolean second) {
        this.id = id;
        this.text = text;
        this.second = second;
    }

    // getters and setters
}

そして、あなたのクエリを変更します。

@Query("SELECT new com.example.demo.SimpleEntityDTO(m.id, m.text, false) FROM SimpleEntity m")
List<SimpleEntityDTO> getRecordsExtended();

これが生成します。

select
    simpleenti0_.id as col_0_0_,
    simpleenti0_.text as col_1_0_,
    0 as col_2_0_ 
from
    simple_entity simpleenti0_

総説

私は予測のエンティティ上のDT​​Oを使用しての理由の一つは、彼らが管理されていないということであると信じています。エンティティは、DTOの一部であり、あなたのケースでは、エンティティが管理されます。

@Transactional
public void changeValueInFirstRecord() {
    List<Pair<SimpleEntity, Boolean>> all = simpleEntityRepository.getRecords();
    SimpleEntity firstEntity = all.get(0).getFirst();
    boolean managed = entityManager.contains(firstEntity);
    System.out.println("managed: " + managed);  // true
    firstEntity.setText("new value");           // firstEntity is updated
}

同じことが、結果変圧器の場合に当てはまります。

@Transactional
public void changeValueInFirstEntityViaTransformer() {
    List<Pair<SimpleEntity, Boolean>> all = entityManager.createQuery(
            "select m as first, false as second from SimpleEntity m")
            .unwrap(org.hibernate.query.Query.class)
            .setResultTransformer(Transformers.aliasToBean(Pair.class))
            .getResultList();
    SimpleEntity firstEntity = all.get(0).getFirst();
    boolean managed = entityManager.contains(firstEntity);
    System.out.println("managed: " + managed);  // true
    firstEntity.setText("new_value");           // firstEntity is updated
}

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=370756&siteId=1