4

基準クエリを使用してリスト属性をフェッチするときに、JPA 2 で予期しない動作と思われるものを観察しています。

私のクエリは次のとおりです(抜粋):

CriteriaBuilder b = em.getCriteriaBuilder();
CriteriaQuery<MainObject> c = b.createQuery(MainObject.class);
Root<MainObject> root = c.from(MainObject.class);
Join<MainObject, FirstFetch> firstFetch = (Join<MainObject, FirstFetch>) root.fetch(MainObject_.firstFetch);
firstFetch.fetch(FirstFetch_.secondFetch); //secondFetch is a list
c.select(root).distinct(true);

(つまり、オブジェクトのプロパティのプロパティとしてリストを取得しているとしましょう。)

問題は、クエリが複数の結果を返す場合、行が返される回数だけ secondFetch の値が複製されることです。各firstFetchには、 secondFetchを 1 つだけ指定する必要がありますが、代わりにnを指定します。この場合の唯一の特徴は、すべての MainObjectsがたまたま同じ FirstFetch インスタンスを持っていることです。したがって、私の推測では、通常は結合が交差していますが、JPA はそのsecondFetchオブジェクトを firstFetchs のそれぞれ割り当てることができません。

マッピングはあまり特別であってはなりません。多かれ少なかれこのようなものです

@Entity
@Table(name="mainobject")
public class MainObject{
   //...
   private FirstFetch firstFetch;

   @ManyToOne(fetch=FetchType.LAZY)
   @JoinColumn(name="mainObject_column")
   public FirstFetch getFirstFetch() {
    return firstFetch;
   }
}

@Entity
@Table(name="firstFetch")
public class FirstFetch{
   //...
   private List<SecondFetch> secondFetch;

   @OneToMany(mappedBy="secondFetch")
   public List<SecondFetch> getSecondFetch() {
      return secondFetch;
   }
}

& 最後に

@Entity
@Table(name="secondFetch")
public class SecondFetch {
    //....
    private FirstFetch firstFetch; //bidirectional

     @ManyToOne
     @JoinColumn(name="column")
     public FirstFetch getFirstFetch() {
        return firstFetch;
     }
}

フェッチに適用するある種の明確な文を探していましたが、何もありません(とにかく「パッチ」だったでしょう...)

私が変われば

List<SecondFetch>

為に

Set<SecondFetch>

Sets' Keysのおかげで期待どおりの結果が得られるので、これは JPA のリストでは一種の不正行為であると感じています。

ただし、私は専門家ではないので、マッピングやクエリで間違いを犯している可能性があります。これを解決するために、どんなフィードバックでも大歓迎です。ありがとう。

4

1 に答える 1

8

JPA基準APIを使用してクエリを実行していましたが、まったく同じ問題がありました。

いくつかの調査の後、私はあなたがすでに言及した解決策を見つけました(ただし、基準APIを使用していないため、利用できませんでした): Using distinct.

JPA基準では、次のようになります。

CriteriaQuery<FirstFetch> query = cb.createQuery(FirstFetch.class);
Root<AbschnittC> root = query.from(FirstFetch.class);
root.fetch(FirstFetch_.secondFetch, JoinType.LEFT);
query.distinct(true); 

結果セットを使用しないquery.distinct(true);と、リスト内のオブジェクトの量が乗算されsecondFetchます。

Hibernate にはDISTINCT_ROOT_ENTITY、クエリを個別に設定するよりも適切に聞こえるようなものがあります。しかし、私はこれをさらに調査していません。また、JPA プロバイダーとして Hibernate を使用しています。queryJPAでdistinctを設定すると、Hibernatesと同じコードを使用することになるのDISTINCT_ROOT_ENTITYでしょうか?

于 2012-04-19T10:30:38.350 に答える