Запрос критериев гибернации для таблицы сбора? - PullRequest
8 голосов
/ 07 октября 2011

У меня есть следующая сущность

@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);

Но при получении org.hibernate.MappingException: коллекция не была ассоциацией: исключение ..

РЕДАКТИРОВАТЬ Поэтому после указания jbrookover я попытался перейти накласс-оболочка для Action, названный как 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);

Но это возвращает мне все правило, которое имеет EMAIL или POSTAL, но чтоЯ хочу, чтобы все правила содержали EMAIL и POSTAL и . Пожалуйста, помогите мне изменить запрос.

Ответы [ 3 ]

6 голосов
/ 10 октября 2011

Извините, то, что вы пытаетесь сделать, в частности, не поддерживается в Hibernate.См. Этот 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

Я тоже был весьма недоволен этим.Однако, как вы можете видеть, они пытались это исправить, но не смогли этого сделать, и обратились к сообществу, чтобы разобраться с этим.У вас есть несколько вариантов:

  1. Использовать HQL для выполнения запроса.
  2. Переписать ассоциацию коллекции как фактический класс сущностей с одним полем Enum.

Вы можете сделать что-то вроде этого:

 @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);

В конце вы можете найти дубликаты результатов.Это обычное явление, и его можно устранить, добавив следующее:

 criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

Я не могу говорить об эффективности этого кода - HQL может быть лучше в долгосрочной перспективе.Однако я делал нечто подобное в других проектах и ​​не сталкивался с какими-либо проблемами.

3 голосов
/ 06 марта 2013

Другое решение без упаковки ваших перечислений и использования 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;

Запрос:

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);

Это то, что мне помогло с Hibernate 4.1.6.Final.Я нашел это здесь .

1 голос
/ 08 октября 2011

Критерий запроса выглядит нормально.Предположим, у нас есть таблицы:

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;
   ...
}

Таким образом, ваш запрос критериев должен работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...