【问题标题】:JPA Criteria Query over an entity hierarchy using single table inheritance使用单表继承对实体层次结构进行 JPA 标准查询
【发布时间】:2014-10-26 19:12:05
【问题描述】:

假设我有以下实体:

@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
));

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

【问题讨论】:

    标签: java jpa criteria-api


    【解决方案1】:

    我设法通过将 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")
    ));
    

    【讨论】:

    • 不工作它给出了 null.someDate 和 null.otherDate,非法错误
    • 它现在工作了,我不知道是什么问题,但它突然开始工作了
    • 如果您只想选择那些特定类型的实体而不想强制执行任何其他条件怎么办?
    【解决方案2】:

    试试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);
    

    我希望你的问题是正确的。

    【讨论】:

    • 该解决方案完全基于 Hibernate,但我正在寻找基于 JPA Criteria API 的解决方案。另外,我宁愿使用 JPA2 元模型来引用属性而不是字符串标识符。
    • 操作询问JPA的问题,而不是休眠。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2023-04-09
    相关资源
    最近更新 更多