Criteria Query API + RAD/Dali が自動生成した、WebSphere v8.0.0.5 の OpenJPA 2.1.2-SNAPSHOT 用の静的正規メタモデルを使用して、次の作業クエリを複製しようとしています。
`SELECT *
FROM CENTER c
INNER JOIN STATE s ON s.ID = c.STATE_ID
INNER JOIN HOURS_OF_OPERATION h ON h.CENTER_ID = c.ID
WHERE c.CITY = '<city_name_here>'
ORDER BY h.WEEKDAY_NUMBER;`
このクエリのコアを形成する 4 つのエンティティがあります。
- Center.java
- 状態.java
- HoursOfOperation.java
- HoursOfOperationPK.java
州ごとに多くのセンターがあります。センターごとに多くの HoursOfOperations があります。センター情報、州の省略形、および月曜から日曜を表す曜日番号 1 から 7 で ASC でソートされたセンターの営業時間で構成される結果セットを返す必要があります。
これが私の方法です:
public Center getCenterInfo(String centerCityName) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Center> cq = cb.createQuery(Center.class);
Metamodel m = em.getMetamodel();
EntityType<Center> _center = m.entity(Center.class);
EntityType<State> _state = m.entity(State.class);
Root<Center> center = cq.from( _center );
Join<Center, State> state = center.join( Center_.state );
Join<Center, HoursOfOperation> hop = center.join( Center_.hoursOfOperations );
cq.select(center).distinct(true);
Predicate predicate = cb.equal(center.get(Center_.city), centerCityName);
cq.where(predicate);
//cq.orderBy(cb.asc(hop.get(HoursOfOperation_.id)));<---Can't access PK field here
center.fetch( Center_.state );
center.fetch( Center_.hoursOfOperations );
TypedQuery<Center> query = em.createQuery( cq );
Center centerInfo = query.getSingleResult();
return centerInfo;
}
私は立ち往生している行をコメントアウトしました。私が使用した方法と同じように、何らかのメソッドを呼び出して、ある種の HoursOfOperationPK インスタンスをインスタンス化する必要があると思いますJoin<Center, HoursOfOperation> hop
。そうすることで、次のようなものを使用できるようになると思いcq.orderBy(cb.asc(hopPk.get(HoursOfOperationPK_.weekdayNumber)));
ます。
次に、 を使用しない場合cq.select(center).distinct(true);
、7 レコードではなく 49 レコードが返されます。何故ですか?レコード数を 7 に減らす唯一の方法は、select に個別のメソッドを追加することです。DISTINCT が SQL で何をするかは理解していますが、ANSI スタイルの SQL 構文では 7 レコードしか返されません。
OpenJPA ログ出力は、OrderBy が HoursOfOperation.centerId に適用されていることを示しています。
HoursOfOperation および HoursOfOperationPK エンティティの関連部分は次のとおりです。
@Entity
@Table(name="HOURS_OF_OPERATION")
public class HoursOfOperation implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private HoursOfOperationPK id;
public HoursOfOperationPK getId() {
return this.id;
}
public void setId(HoursOfOperationPK id) {
this.id = id;
}
}
@Embeddable
public class HoursOfOperationPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
@Column(name="CENTER_ID", unique=true, nullable=false)
private long centerId;
@Column(name="WEEKDAY_NUMBER", unique=true, nullable=false)
private long weekdayNumber;
public HoursOfOperationPK() {
}
public long getCenterId() {
return this.centerId;
}
public void setCenterId(long centerId) {
this.centerId = centerId;
}
public long getWeekdayNumber() {
return this.weekdayNumber;
}
public void setWeekdayNumber(long weekdayNumber) {
this.weekdayNumber = weekdayNumber;
}
}
EDIT @perissf ASC を使用して明示的な順序なしで目的の結果を生成することができました (weekdayNumber が営業時間テーブルの複合主キーの一部であるため、ソートが暗黙的に発生するようです。明示的なソートが必要です)ただし、それほど幸運ではない可能性がある他のクエリに役立つ可能性があるためです):
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Center> cq = cb.createQuery(Center.class);
Metamodel m = em.getMetamodel();
EntityType<Center> _center = m.entity(Center.class);
Root<Center> center = cq.from( _center );
Expression<List<HoursOfOperation>> hop = center.get( Center_.hoursOfOperations );
cq.select(center);
Predicate predicate = cb.equal(center.get(Center_.city), centerCityName);
cq.where(predicate);
center.fetch( Center_.state );
center.fetch( Center_.hoursOfOperations );
TypedQuery<Center> query = em.createQuery( cq );
Center centerInfo = query.getSingleResult();
ただし、次を使用して目的の SQL を生成することもできましたが、唯一の問題は、センターの HoursOfOperation が設定されていないことです (遅延読み込みが原因で、center.Fetch(Center_.hoursOfOperation)
重複したレコードが作成されました。解決策はありますか?):
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Center> cq = cb.createQuery(Center.class);
Metamodel m = em.getMetamodel();
EntityType<Center> _center = m.entity(Center.class);
Root<Center> center = cq.from( _center );
EntityType<HoursOfOperation> _hoo = m.entity(HoursOfOperation.class);
Root<HoursOfOperation> hoo = cq.from( _hoo );
cq.select(center).distinct(true);
Predicate predicate = cb.and(cb.equal(center.get(Center_.city), centerCityName),
cb.equal(center, hoo.get(HoursOfOperation_.center)));
cq.where(predicate);
cq.orderBy(cb.asc(hoo.get( HoursOfOperation_.id ).get(HoursOfOperationPK_.weekdayNumber)));
center.fetch( Center_.state );
TypedQuery<Center> query = em.createQuery( cq );
Center centerInfo = query.getSingleResult();