收集表的Hibernate条件查询?

时间:2011-10-07 12:42:13

标签: hibernate hibernate-criteria

我有以下实体

@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:collection不是关联:exception ..

修改 的 因此,在jbrookover的指导下,我尝试使用名为RuleAction的Action的包装类,并且能够实现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 个答案:

答案 0 :(得分:6)

很抱歉,Hibernate不支持您尝试执行的操作。请参阅此常见问题解答:

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. 将您的集合关联重写为具有单个枚举字段的实际实体类。
  3. 您可以这样做:

     @Entity
     public class ActionWrapper {
    
          public Action action;
     }
    

    然后,相应地更新您的关联和查询,以便Rule具有Set<ActionWrapper>。还有其他解决方法,但您基本上不能同时使用Criteria@ElementCollection

    <强>更新

    为了进一步限制查询,为了确保获得满足BOTH操作的规则,您需要运行子查询并对匹配的值进行连接 - “和”。这样的事情应该有效:

     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可能会更好。但是,我在其他项目中做过类似的事情,并没有遇到任何问题。

答案 1 :(得分:3)

没有包装您的枚举和使用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有用。我找到了here

答案 2 :(得分:1)

条件查询看起来很好。假设我们有表:

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

这样您的条件查询就可以了。