I have following Entity
@Entity
@Table(name = \"rule\")
public class Rule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AU
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.
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:
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.