【问题标题】:Hibernate criteria on collection values集合值的休眠条件
【发布时间】:2011-06-17 14:08:25
【问题描述】:

我正在尝试使用 Hibernate 组合一个复杂的查询。我一直倾向于 Criteria,但我开始怀疑这是不可能的,因此任何建议都会有所帮助。

我有一个如下的实体结构:

public class Attribute {
    private Integer id;
    private String name;
    private Set<Value> values;
}

public class Instance {
    private Integer id;
    private int instanceRef;
    private Set<Value> values;
}

public class Value {
    private Integer id;
    private Attribute attribute;
    private String localAttributeName;
    private Instance instance;
    private String value;
}

这些实体是相关的,如您所料:

value.attribute_id --> attribute.id
value.instance_id --> instance.id

现在,我希望能够获取一组属性/值对(字符串)并找到包含 all 的所有实例。在 Value 中,attribute 和 localAttributeName 只有一个是非空的,因此属性名称可以匹配 localAttributeName 或 attribute.name。最后一次让事情复杂化的是,Value 的唯一索引是 on (instance, attribute, value) 或 (instance, localAttributeName, value)——也就是说,在一个实例中,任何给定的属性都可能有多个值。

这是我目前所拥有的:

public List<Instance> getMatchingInstances(Map<String, String> attrValues) {
    Criteria crit = session.createCriteria(Instance.class, "i");
    for(Map.Entry<String, String> entry : attrValues) {
        DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v");

        // Do something here with valueCrit

        crit.add(Subqueries.exists(valueCrit));
    }
    return crit.list();
}

根据我所做的研究,我为“做某事”部分所做的尝试是:

    // This would only check localAttributeName and not attribute.name.
    // That's okay -- once I get the rest to work, I can figure this out.
    valueCrit.add(Restrictions.eq("localAttributeName", entry.getKey());
    valueCrit.add(Restrictions.eq("value", entry.getValue());
    valueCrit.add(Restrictions.eqProperty("v.instance_id", "i.id"));

但这会引发下面的异常,我怀疑这告诉我我不能使用 Criteria 执行此操作,但我很想学习其他方法:

java.lang.NullPointerException
    at org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes(CriteriaQueryTranslator.java:341)

最好的方法是什么?

【问题讨论】:

    标签: java hibernate orm hibernate-criteria


    【解决方案1】:

    经过几个小时的尝试,我找到了解决方案。希望这对其他人有用。为了使之可行,我需要解决三个要点:

    1. 添加投影
    2. 创建正确的连接
    3. 将子查询正确映射回主要条件

    我已经在下面的代码中突出显示了这些。

    首先,为了摆脱异常,我发现子查询需要一个投影,如下所示。我刚刚对 Instance 的“id”属性做了一个投影。

    其次,为了获得连接,我使用 Criteria.createCriteria() 方法创建了一个左外连接。因为我在连接的不同级别有多个条件,所以我必须保存连接的 Criteria 并将表达式分别附加到它们。这让我可以在子查询中执行 OR 表达式。

    最后,我必须添加一个 eqProperty() 子句来将子查询映射回主 Criteria。就像它需要在生成的 SQL 中一样,我使用了:instance.id = i.id。因为我已经将 Instance Criteria 映射到“i”,并将这个子句添加到 Value Criteria,所以这转换为 SQL:v.instance_id = i.id。

    这是工作代码:

    public List<Instance> getMatchingInstances(Map<String, String> attrValues) {
        Criteria crit = session.createCriteria(Instance.class, "i");
        for(Map.Entry<String, String> entry : attrValues) {
            String attrName = entry.getKey();
            String val = entry.getValue();
    
            // Create the subquery
            DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v");
    
            // Join the Attribute object (left outer join)
            DetachedCriteria attrCrit = 
              valueCrit.createCriteria("attribute", CriteriaSpecification.LEFT_JOIN);
    
            // Put together the OR statement on the Attribute joined criterion.
            Criterion localAttr = Restrictions.eq("v.localAttributeName", attrName);
            Criterion globalAttr = Restrictions.eq("name", attrName);
            attrCrit.add(Restrictions.or(localAttr, globalAttr));
    
            // Simple column equality on the subquery criterion.
            valueCrit.add(Restrictions.eq("value", val));
    
            // Map the subquery back to the outer query.
            valueCrit.add(Restrictions.eqProperty("instance.id", "i.id"));
    
            // Add the missing projection.
            valueCrit.setProjection(Projections.property("id"));
    
            // Add this subquery to the outer query.
            crit.add(Subqueries.exists(valueCrit));
        }
        return crit.list();
    }
    

    【讨论】:

    猜你喜欢
    • 2011-02-25
    • 2011-12-02
    • 1970-01-01
    • 2013-03-20
    • 2018-03-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多