Hibernate criteria on collection values

后端 未结 1 350
猫巷女王i
猫巷女王i 2020-12-14 11:11

I\'m trying to put together a complicated query using Hibernate. I\'ve been leaning toward Criteria, but I\'m beginning to suspect it\'s not possible, and so any suggestions

相关标签:
1条回答
  • 2020-12-14 11:44

    I figured out the solution after a few hours of banging on it. Hopefully, this is of use to others. There were three main points that I needed to solve to make this feasible:

    1. Add a Projection
    2. Create the proper joins
    3. Properly map the subquery back to the main criteria

    I've highlighted each of these in the below code.

    First, to get rid of the exception, I discovered that the subquery needed a projection, highlighted below. I just did a projection on the "id" property of Instance.

    Second, to get the join, I used the Criteria.createCriteria() methods to create a left outer join. Because I had multiple conditions at different levels of the join, I had to save the joined Criteria and attach expressions to them separately. This let me do my OR expression in the subquery.

    Finally, I had to add an eqProperty() clause to map the subquery back to the main Criteria. Just like it would need to be in the resulting SQL, I used: instance.id = i.id. Because I had already mapped the Instance Criteria to "i" and was adding this clause to the Value Criteria, this translated to the SQL: v.instance_id = i.id.

    Here's the working code:

    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();
    }
    
    0 讨论(0)
提交回复
热议问题