JPA条件API查询子类属性

时间:2015-12-13 14:02:00

标签: hibernate jpa inheritance criteria criteria-api

我想执行与特定子类属性匹配的查询,因此我尝试使用treat()

在这个例子中我想要:

名称以' a',
开头的所有科目 或所有科目,即人,姓氏以' a'

开头
private List<Subject> q1()
{
    CriteriaBuilder b = em.getCriteriaBuilder();

    CriteriaQuery<Subject> q = b.createQuery(Subject.class);
    Root<Subject> r = q.from(Subject.class);
    q.select(r);
    q.distinct(true);
    q.where(
        b.or(
            b.like(r.get(Subject_.name), "a%"),
            b.like(b.treat(r, Person.class).get(Person_.lastName), "a%")));

    return em.createQuery(q).getResultList();
}

显然,Person扩展SubjectSubject是抽象的,继承为SINGLE_TABLESubject@DiscriminatorOptions(force = true)为其他原因(非流入)。

但生成的SQL是这样的:

select distinct subject0_.ID as ID2_71_, subject0_.CODE as CODE3_71_, ...
from SUBJECT subject0_ 
where subject0_.DTYPE='Person' and (subject0_.name like 'a%' or subject0_.lastName like 'a%')

虽然我期待:

select distinct subject0_.ID as ID2_71_, subject0_.CODE as CODE3_71_, ...
from SUBJECT subject0_ 
where subject0_.name like 'a%' or (subject0_.DTYPE='Person' and subject0_.lastName like 'a%')

有没有办法使用条件构建器生成预期的查询?

请注意

  • 使用其他 Root - q.from(Person.class)
  • 使用子查询 - q.subquery(Person.class)
  • lastName 字段移至主题
  • 使用原生查询
  • 使用实体图

不接受

我对可以直接在 WHERE 子句中声明和使用的内容感兴趣(仅来自 CriteriaBuilder 和/或单个 Root ,就像treat()子句一样),如果它存在的话。

1 个答案:

答案 0 :(得分:4)

<强>更新

你期待的sql - 虽然它可以用纯jpa crtieria api进行生成 - 它不会起作用并且会抛出一个异常,因为你(hibernate)不能实例化抽象类主题。

  

引起:org.hibernate.InstantiationException:无法实例化   抽象类或接口:

如果课程不是抽象的,那就有效。像这样:

CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Contact> q;
q = b.createQuery(Contact.class);
Root r = q.from(Contact.class);

   q.select(r);
   q.distinct(true);
q.where(
        b.or(
                b.like(r.get(Contact_.name),"t%"),
                b.and(
                        b.equal(r.get(Contact_.contact_type),"customer"),
                        b.like(r.get(Customer_.lastName),"t%")
                )
        )
);

return getEntityManager().createQuery(q).getResultList();

(我的客户是您的人,我的主题类是联系人类)

以只读方式访问鉴别器列可能是一种有效的解决方法。 如果discriminator_column是contact_type,请执行:

@Column(name = "contact_type",insertable = false,updatable = false)
@XmlTransient
private String contact_type;

然后联系成为一个抽象类,客户作为子类如下:

CriteriaBuilder b = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Contact> q = b.createQuery(Contact.class);
           Root<Contact>  r = q.from(Contact.class);
           q.distinct(true);

           q.where(
                b.or(
                        b.like(r.get(Contact_.name), "t%"),
                        b.and(
                                b.equal(r.get(Customer_.contact_type), "customer"),
                                b.like(r.get(Customer_.name), "%t")
                        )
                )
                );
           return getEntityManager().createQuery(q).getResultList();

制作

select

distinct contact0_.id as id2_1_,
    contact0_.contact_type as contact_1_1_,
    contact0_.name as name3_1_ 
from
    Contact contact0_ 
where
    contact0_.name like ? 
    or contact0_.contact_type=? 
    and (
        contact0_.name like ?
    )