JPA Criteria使用单表继承查询实体层次结构

时间:2014-09-02 13:36:15

标签: java jpa criteria-api

说我有以下实体:

@Entity
@Inheritance(strategy = SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
public abstract class BaseEntity { 
    private Date someDate;
    private Date otherDate;
    private boolean flag;
}

@Entity
@DiscriminatorValue("entity1")
public class Entity1 extends BaseEntity { 
    private String someProperty;
}

@Entity
@DiscriminatorValue("entity2")
public class Entity2 extends BaseEntity { 
    private String otherProperty;
}

我尝试构建一个条件查询,该查询根据BaseEntity中的属性和两个子类返回BaseEntity实例。所以基本上我正在寻找与这个伪SQL相对应的标准查询:

SELECT * FROM <BaseEntity table name>
WHERE someDate < ? AND otherDate > ? AND flag = ?
AND someProperty = ? AND otherProperty = ?;

我宁愿不构建两个单独的查询,因为它们有很多重叠(即大多数属性都在基类中)。但是,如果我将BaseEntity声明为根,我还没有找到一种方法来引用查询中的子类属性。是否可以建立这样的标准查询?

更新

也许某些代码会澄清这个问题。我基本上喜欢做这样的事情:

CriteriaBuilder builder = ...;
CriteriaQuery<BaseEntity> query = ...;
Root<BaseEntity> root = ...;

query.select(root).where(builder.and(
        builder.lessThan(root.get(BaseEntity_.someDate), new Date()),
        builder.greaterThan(root.get(BaseEntity_.otherDate), new Date()),
        builder.isTrue(root.get(BaseEntity_.flag)),
        builder.equal(root.get(Entity1_.someProperty), "foo"),   <-- This won't work
        builder.equal(root.get(Entity2_.otherProperty), "bar")   <-- Neither will this
));

现在,我理解为什么上面的代码示例不起作用,但我想知道是否有办法绕过它。

2 个答案:

答案 0 :(得分:11)

我设法通过将BaseEntity根目录转换为与CriteriaBuilder.treat()类似的子类类型对应的新根来解决这个问题:

CriteriaBuilder builder = ...;
CriteriaQuery<BaseEntity> query = ...;
Root<BaseEntity> root = ...;
Root<Entity1> entity1 = builder.treat(root, Entity1.class);
Root<Entity2> entity2 = builder.treat(root, Entity2.class);

query.select(root).where(builder.and(
        builder.lessThan(root.get(BaseEntity_.someDate), new Date()),
        builder.greaterThan(root.get(BaseEntity_.otherDate), new Date()),
        builder.isTrue(root.get(BaseEntity_.flag)),
        builder.equal(entity1.get(Entity1_.someProperty), "foo"),
        builder.equal(entity2.get(Entity2_.otherProperty), "bar")
));

答案 1 :(得分:-1)

试试Junction。你可以做这样的事情:

Criteria crit = session.createCriteria(YourClassName.class);
Criterion cr1 = Restrictions.lt("propertyname", propertyvalue);
Criterion cr2 = Restrictions.gt("propertyname", propertyvalue);
Criterion cr3 = Restrictions.eq("propertyname", propertyvalue);
Criterion cr4 = Restrictions.eq("propertyname", propertyvalue);
Junction cond = Restrictions.conjunction();
cond.add(cr1).add(cr2).add(cr3).add(cr4)
crit.add(cond);

我希望我能正确地得到你的问题。