Запрос критериев гибернации для таблицы коллекции?
У меня есть следующая сущность
@Entity
@Table(name = "rule")
public class Rule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "rule_id")
private Long id;
@ElementCollection(targetClass = Action.class)
@CollectionTable(name = "rule_action", joinColumns = @JoinColumn(name = "rule_id"))
@Enumerated(value = EnumType.STRING)
@Column(name = "action")
private Set<Action> actions;
//After editing as per jbrookover's suggestion adding a new mapping
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "rule_id")
private Set<RuleAction> ruleActions;
}
Следование - это мое действие
public enum Action {
PHONE, EMAIL, POSTAL,PHONE_OR_EMAIL, SMS;
}
Я хочу получить список правил, имеющих определенный набор действий Я пытаюсь это сделать
DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class,"rule");
criteria = criteria.createAlias("rule.actions", "action");
criteria.add(Restrictions.in("action.name",actionSet));
return getHibernateTemplate().findByCriteria(criteria);
Но получение орг..зимовать.MappingException: collection не был ассоциацией: исключение..
EDIT Поэтому после руководства от jbrookover я попытался перейти к классу-оболочке для действия с именем RuleAction и смог установить отношение oneToMany, также я изменил запрос выглядит следующим образом
Set<Action> act = new HashSet<Action>();
act.add(Action.EMAIL);
act.add(Action.POSTAL);
DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class);
criteria.add(Restrictions.eq(SUPPORT_LANG, Language.valueOf("EN")))
.createCriteria("ruleActions").add(Restrictions.in("action",act));
return getHibernateTemplate().findByCriteria(criteria);
Но это возвращает мне все правила, которые имеют либо электронную почту, либо почтовые, но то, что я хочу, это все правила, имеющие электронную почту и почтовые оба Пожалуйста, помогите мне в изменении запроса.
3 ответа:
Извините, то, что вы пытаетесь сделать, в частности, не поддерживается в режиме гибернации. Смотрите этот FAQ:
Я тоже был этим весьма недоволен. Как вы можете видеть, однако, они пытались исправить это, но не смогли этого сделать и поставили это на сообщество, чтобы иметь дело с ним. У вас есть несколько вариантов:
- используйте HQL для выполнения запроса.
- перепишите ассоциацию коллекции как фактический класс сущностей с одним полем перечисления.
Вы можете сделать что-то вроде этого:
@Entity public class ActionWrapper { public Action action; }
Затем обновите свои ассоциации и запрос соответственно, чтобы
Rule
имелSet<ActionWrapper>
. Есть и другие обходные пути, но вы, по существу, не можете использоватьCriteria
и@ElementCollection
вместе.Обновить
Для дальнейшего ограничения запроса, чтобы убедиться, что вы получаете правила, соответствующие обоим действиям, вам нужно запустить подзапрос и выполнить соединение - 'и' - соответствующих значений. Что-то вроде этого должно сработать:
В конце концов, вы можете найти дублирующиеся результаты. Это обычное явление, и его можно устранить, добавив следующее:Criteria subCriteria = criteria.createCriteria("ruleActions"); Disjunction and = Restrictions.conjunction(); for (Action a : act) and.add(Restrictions.eq("action", a) subCriteria.add(and);
Я не могу говорить за эффективность этого кода - HQL может быть лучше в долгосрочной перспективе. Однако я делал нечто подобное в других проектах и не сталкивался с какими-либо проблемами.criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Еще одно решение без обертывания перечислений и использования ResultTransformers выглядит следующим образом:
@ElementCollection(fetch = FetchType.EAGER) @Enumerated(value = EnumType.STRING) @Column(name = " action") @JoinTable(name = "rule_action", joinColumns = { @JoinColumn(name = "rule_id") }) private Set<Action> actions;
Запрос:
Это то, что сработало для меня с Hibernate 4.1.6.Окончательный. Я нашел его здесь .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);
Запрос критериев выглядит нормально. Предположим, что у нас есть таблицы:
rule(id, name,...) action(id, name,..) rule_action(id, rule_id, action_id,...) -- (or rule_id+action_id as a composite pkey)
Отображение должно быть следующим:
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; ... }
Таким образом, ваш запрос критериев должен работать.