Hibernate Criteria API - 添加一个标准:字符串应该在集合中

Posted

技术标签:

【中文标题】Hibernate Criteria API - 添加一个标准:字符串应该在集合中【英文标题】:Hibernate Criteria API - adding a criterion: string should be in collection 【发布时间】:2011-02-13 16:07:50 【问题描述】:

我必须关注实体对象

@Entity public class Foobar ... private List<String> uuids; ...

现在我想做一个标准查询,它会获取所有 Foobar pojos,其 uuids 列表包含字符串“abc123”,我只是不确定如何制定适当的标准。

【问题讨论】:

【参考方案1】:

我假设您使用的是实现 JPA 2.0 的 Hibernate 版本。这是一个 JPA 2.0 解决方案,应该适用于任何兼容的实现。

请使用 JPA 的 @ElementCollection 注释来注释 uuids。不要使用 Hibernate 的 @CollectionOfElements,正如其他一些答案 cmets 中提到的那样。后者具有相同的功能,但为being deprecated。

Foobar.java 大致如下:

@Entity
public class Foobar implements Serializable 

    // You might have some other id
    @Id
    private Long id;

    @ElementCollection
    private List<String> uuids;

    // Getters/Setters, serialVersionUID, ...


以下是构建CriteriaQuery 以选择uuids 包含“abc123”的所有Foobars 的方法。

public void getFoobars() 

    EntityManager em = ... // EM by injection, EntityManagerFactory, whatever

    CriteriaBuilder b = em.getCriteriaBuilder();
    CriteriaQuery<Foobar> cq = b.createQuery(Foobar.class);
    Root<Foobar> foobar = cq.from(Foobar.class);

    TypedQuery<Foobar> q = em.createQuery(
            cq.select(foobar)
              .where(b.isMember("abc123", foobar.<List<String>>get("uuids"))));

    for (Foobar f : q.getResultList()) 
        // Do stuff with f, which will have "abc123" in uuids
    

我在玩这个的时候做了一个独立的概念验证程序。我现在推不出来。如果您想将 POC 推送到 github,请发表评论。

【讨论】:

用hibernate 3.6.7-Final试过了,还是不行(好像是hibernate的bug)。【参考方案2】:

我知道这是一个老问题,但我刚刚遇到这个问题并找到了解决方案。

如果你想使用 Hibernate Criteria,你可以加入你的 uuids 集合并使用它的属性 elements 来匹配元素。就这样:

session.createCriteria(Foobar.class)
    .createAlias("uuids", "uuids")
    .add(Restrictions.eq("uuids.elements", "MyUUID"))
    .list() 

【讨论】:

你也可以使用常量CollectionPropertyNames.COLLECTION_ELEMENTS来代替“元素”。【参考方案3】:

您可以使用下面示例中的查询,也可以将其转换为 NamedQuery。不幸的是,Criteria 似乎没有办法做到这一点。

List<Foobar> result = session
     .createQuery("from Foobar f join f.uuids u where u =: mytest")
     .setString("mytest", "acb123")
     .list();

【讨论】:

【参考方案4】:

我发现了一年前的这篇文章,并且我制作了这个方法,如果它可以帮助任何人解决我几个小时前遇到的同样问题。

    Public List<EntityObject> getHasString(String string) 
        return getSession().createCriteria(EntityObject.class)
                               .add(Restriction.like("property-name", string, MatchMode.ANYWHERE).ignoreCase();
                           .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                           .list();

用一组字符串也一样。

    public List<EntityObject> getByStringList(String[] tab) 
        Criterion c = Restrictions.like("property-name", tab[tab.length-1], MatchMode.ANYWHERE).ignoreCase();
        if(tab.length > 1) 
            for(int i=tab.length-2; i >= 0 ; i--) 
                c = Restrictions.or(Restrictions.like("property-name",tab[i], MatchMode.ANYWHERE).ignoreCase(), c);
            
        
        return getSession().createCriteria(EntityObject.class)
                               .add(c)
                           .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                           .list();
    

它适用于“or”语句,但可以很容易地被“and”语句替换。

【讨论】:

【参考方案5】:

hibernate 不支持您的要求。见http://opensource.atlassian.com/projects/hibernate/browse/HHH-869

这是 jira 票证中可用的解决方法:

entityCriteria.add(Restrictions.sqlRestriction(
  "fooAlias.id in (select e.id from foobar_table e, values_table v" + 
  " where e.id = v.entity_id and v.field = ?)", "abc123"), Hibernate.String)) ;

【讨论】:

【参考方案6】:

jira 的 sqlRestriction 解决方案 http://opensource.atlassian.com/projects/hibernate/browse/HHH-869 对我来说似乎是最好的方式,因为我大量使用标准 api。我不得不编辑 Thierry 的代码,所以它适用于我的情况

型号:

@Entity
public class PlatformData

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long iID;

  private List<String> iPlatformAbilities = new ArrayList<String>();

标准调用:

tCriteria.add(Restrictions.sqlRestriction(
        "alias.id in (select e.id from platformData e, platformdata_platformabilities v"
          + " where e.id = v.platformdata_id and v.element = ? )", aPlatformAbility.toString(),
        Hibernate.STRING));

【讨论】:

【参考方案7】:

对于初学者,我认为 Hibernate 不能映射 List&lt;String&gt;。但是,它可以映射其他实体的列表。

如果你的代码是这样的:

@Entity
public class Foobar 

    private List<EntityObject> uuids;
    ...

EntityObject 有一个名为Stringstr 属性,标准可能如下所示:

List<Foobar> returns = (List<Foobar>) session
                .createCriteria.(Foobar.class, "foobars")
                .createAlias("foobars.uuids", "uuids")
                  .add(Restrictions.like("uuids.str", "%abc123%"))
                .list();

【讨论】:

使用字符串列表没有问题,只要用@CollectionOfElements注解即可。您的解决方案需要我创建一个额外的实体类,我希望通过这个非常具体的问题来避免这种情况。

以上是关于Hibernate Criteria API - 添加一个标准:字符串应该在集合中的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate Criteria API:获取 n 个随机行

Hibernate Criteria Api 是不是完全防止 SQL 注入

(懒惰)使用 Hibernate Criteria API 的 LEFT OUTER JOIN

Criteria API JPA Hibernate:外键上的不同选择

如何使用 JPA Criteria API / Hibernate 按 Case 语句分组

使用Criteria API的Hibernate向数据库发送了太多查询