title: Hibernate criteria on collection values
body: <p>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 would be helpful.</p>
  
  <p>I have an entity structure like the following:</p>
  
  <pre><code>public class Attribute {
      private Integer id;
      private String name;
      private Set&lt;Value&gt; values;
  }
  
  public class Instance {
      private Integer id;
      private int instanceRef;
      private Set&lt;Value&gt; values;
  }
  
  public class Value {
      private Integer id;
      private Attribute attribute;
      private String localAttributeName;
      private Instance instance;
      private String value;
  }
  </code></pre>
  
  <p>These entities are related as you'd expect:</p>
  
  <pre><code>value.attribute_id --&gt; attribute.id
  value.instance_id --&gt; instance.id
  </code></pre>
  
  <p>Now, I would like to be able to take a set of attribute/value pairs (Strings) and find all instances that contain <em>all</em> of them. In Value, only one of attribute and localAttributeName are non-null, so the attribute name may match either localAttributeName or attribute.name. And to complicate things one last time, the unique index on Value is on (instance, attribute, value) or (instance, localAttributeName, value) -- that is, within an Instance, any given Attribute may have multiple Values.</p>
  
  <p>This is what I have so far:</p>
  
  <pre><code>public List&lt;Instance&gt; getMatchingInstances(Map&lt;String, String&gt; attrValues) {
      Criteria crit = session.createCriteria(Instance.class, "i");
      for(Map.Entry&lt;String, String&gt; entry : attrValues) {
          DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v");
  
          // Do something here with valueCrit
  
          crit.add(Subqueries.exists(valueCrit));
      }
      return crit.list();
  }
  </code></pre>
  
  <p>Based on the research I've done, what I've tried for that Do something section is:</p>
  
  <pre><code>    // 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"));
  </code></pre>
  
  <p>But this throws the exception below, which I suspect is telling me I can't do this with Criteria, but I'd love to learn otherwise:</p>
  
  <pre><code>java.lang.NullPointerException
      at org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes(CriteriaQueryTranslator.java:341)
  </code></pre>
  
  <p>What would be the best way to go about doing this?</p>