Hibernate criteria query for Collection Table?

老子叫甜甜 提交于 2019-11-28 10:10:12

Sorry, what you are trying to do, specifically, is not supported in Hibernate. See this FAQ:

http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Im_getting_orghibernateMappingException_collection_was_not_an_association_when_I_try_to_join_a_collection_of_components_with_Criteria_queries

I, too, was quite displeased with this. As you can see, though, they've tried to fix it an have been unable to do so and have put it on the community to deal with it. You have a few options:

  1. Use HQL to run the query.
  2. Re-write your collection association as an actual entity class with a single Enum field.

You can do something like this:

 @Entity
 public class ActionWrapper {

      public Action action;
 }

Then, update your associations and query accordingly so that Rule has a Set<ActionWrapper>. There are other workarounds, but you essentially cannot use Criteria and @ElementCollection together.

Update

In order to restrict the query further, to ensure that you get Rules that meet BOTH actions, you need to run the subquery and do a conjunction - 'and' - of the matched values. Something like this should work:

 Criteria subCriteria = criteria.createCriteria("ruleActions");
 Disjunction and = Restrictions.conjunction();
 for (Action a : act)
    and.add(Restrictions.eq("action", a)
 subCriteria.add(and);

At the end, you may find duplicate results. This is common and can be eliminated by adding this:

 criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

I can't speak for the efficiency of this code - HQL may be better in the long run. However, I've done something similar in other projects and haven't encountered any issues.

schnatterer

Another solution without wrapping your enums and using ResultTransformers is this:

        @ElementCollection(fetch = FetchType.EAGER)
        @Enumerated(value = EnumType.STRING)
        @Column(name = " action")
        @JoinTable(name = "rule_action", joinColumns = { @JoinColumn(name = "rule_id") })
        private Set<Action> actions;

Query:

DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class,"rule");
criteria = criteria.createAlias("rule.actions", "action");
criteria.add(Restrictions.in("action." + CollectionPropertyNames.COLLECTION_ELEMENTS, actionSet));
return getHibernateTemplate().findByCriteria(criteria);

That's what worked for me with Hibernate 4.1.6.Final. I found it here.

The criteria query looks fine. Suppose we have tables:

rule(id, name,...)
action(id, name,..)
rule_action(id, rule_id, action_id,...) -- (or rule_id+action_id as  a composite pkey)

The mapping should be as follows:

public class Rule {
   ...
   @ManyToMany(mappedBy = "rule")
   private Set<Action> actions;
   ...
}

public class Action {
   ...
   @JoinTable(
      name="rule_action",
      joinColumns={@JoinColumn(name="action_id")},
      inverseJoinColumns={@JoinColumn(name="rule_id")}
   )
   private Set<Rule> rules;
   ...
}

This way your criteria query should work.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!