web-dev-qa-db-ja.com

JPA-Criteria APIおよびEmbeddedId

条件を使用して次のクエリを作成したいと思います。 EntityEmbeddedIdを定義しています:

 @Entity
 @Table(name="TB_INTERFASES")
 public class Interfase implements Serializable {

  @EmbeddedId
  private InterfaseId id;
 }

 @Embeddable
 public class InterfaseId implements Serializable {
  @Column(name="CLASE")
  private String clase;
 }

そして私がやろうとしている基準クエリは:

 CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
 CriteriaQuery<Interfase> criteriaQuery = criteriaBuilder.createQuery(Interfase.class);
 Root<Interfase> entity = criteriaQuery.from(Interfase.class);
 criteriaQuery.where(
   criteriaBuilder.equal(entity.get("clase"), "Clase"),
 );

しかし、これはIllegalArgumentExceptionをスローしています。

Java.lang.IllegalArgumentException: Not an managed type: class InterfaseId

私もこのクエリを試してみました:

 Root<Interfase> entity = criteriaQuery.from(Interfase.class);
 criteriaQuery.where(
   criteriaBuilder.equal(entity.get("id").get("clase"), "Clase"),
 );

これも….

 Root<Interfase> entity = criteriaQuery.from(Interfase.class);
 criteriaQuery.where(
   criteriaBuilder.equal(entity.get("id.clase", "Clase"),
 );

運がない。だから私の質問は、クラスがEmbeddedおよびEmbeddedIdアノテーションを使用しているときに、どのように基準を使用してクエリを作成できるかということです。

ありがとう!マウロ。

28
Mauro Monti

Embeddableの属性にアクセスするには、パスナビゲーションを使用する必要があります。以下はJPA 2.0仕様の例です(静的メタモデルを使用)。

6.5.5パスナビゲーション

...

次の例では、ContactInfoはアドレスと電話のセットで構成される組み込み可能なクラスです。 Phoneはエンティティです。

CriteriaQuery<Vendor> q = cb.createQuery(Vendor.class);
Root<Employee> emp = q.from(Employee.class);
Join<ContactInfo, Phone> phone =
    emp.join(Employee_.contactInfo).join(ContactInfo_.phones);
q.where(cb.equal(emp.get(Employee_.contactInfo)
                    .get(ContactInfo_.address)
                    .get(Address_.zipcode), "95054"))
    .select(phone.get(Phone_.vendor));

次のJava永続クエリ言語クエリは同等です。

SELECT p.vendor
FROM Employee e JOIN e.contactInfo.phones p
WHERE e.contactInfo.address.zipcode = '95054'

したがって、あなたの場合、次のようなものが必要になると思います:

criteriaBuilder.equal(entity.get("id").get("clase"), "Referencia 111")

参考文献

  • JPA 2.0仕様
    • 6.5.5「パスのナビゲーション」

pdate:提供されたエンティティをHibernate EntityManager 3.5.6と次のクエリでテストしました。

CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Interfase> criteria = builder.createQuery(Interfase.class);
Root<Interfase> interfaseRoot = criteria.from(Interfase.class);
criteria.select(interfaseRoot);
criteria.where(builder.equal(interfaseRoot.get("id").get("clase"), 
    "Referencia 111"));

List<Interfase> interfases = em.createQuery(criteria).getResultList();

正常に実行され、次のSQLが生成されます。

 17:20:26.893 [main] DEBUG org.hibernate.SQL-
 select 
 interfase0_.CLASE as CLASE31_ 
 from 
 TB_INTERFASES interfase0_ 
 where 
 interfase0_.CLASE =?
 17:20:26.895 [main] TRACE org.hibernate.type.StringType-「Referencia 111」をパラメータにバインド:1 

期待どおりに動作します。

59
Pascal Thivent

metamodelクラスをコピーして、エンティティが保存されているのと同じフォルダに貼り付けてください(NetBeans 8.2では、これらは自動的に生成され、エンティティの名前は同じですが、末尾にアンダースコアが付いています。 Interfase_およびInterfaseId_)。

metamodelクラスのインポートを強制するInterfase_およびInterfaseId_をクリックして、目的のフィールドを参照します。

CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Interfase> criteria = builder.createQuery(Interfase.class);
Root<Interfase> interfaseRoot = criteria.from(Interfase.class);
criteria.select(interfaseRoot);
criteria.where(builder.equal(interfaseRoot.get(Interfase_.id).get(InterfaseId_.clase),"Referencia 111"));
List<Interfase> interfases = em.createQuery(criteria).getResultList();
0
MicroCharles

古い質問ですが、とにかく...

別の非常にシンプルなソリューションは

InterfaseId id = new InterfaseId();
id.setClase("Clase");
Interfase found = em.find(id);

あなたが尋ねた以外の何かをしようとする場合を除いて、これはそれを行う「正気な」方法です。 idに対するクエリは、最大1つの結果を返します。

0
Theofanis