【问题标题】:Looking for an HQL builder (Hibernate Query Language)寻找 HQL 构建器(休眠查询语言)
【发布时间】:2010-09-08 13:58:27
【问题描述】:

我正在为HQL 寻找Java 中的构建器。我想摆脱这样的事情:

StringBuilder builder = new StringBuilder()
    .append("select stock from ")
    .append( Stock.class.getName() )
    .append( " as stock where stock.id = ")
    .append( id );

我宁愿有类似的东西:

HqlBuilder builder = new HqlBuilder()
    .select( "stock" )
    .from( Stock.class.getName() ).as( "stock" )
    .where( "stock.id" ).equals( id );

我google了一下,没找到。

我写了一个又快又笨的 HqlBuilder 来满足我现在的需要,但我很想找到一个比我一个人拥有更多用户和测试的人。

注意:我希望能够做这样的事情以及更多,但我未能使用 Criteria API 做这些事情:

select stock
from com.something.Stock as stock, com.something.Bonus as bonus
where stock.someValue = bonus.id

即。从红利表中选择属性someValue 指向任何红利的所有股票。

谢谢!

【问题讨论】:

    标签: java hibernate hql


    【解决方案1】:

    Criteria API 不是为你做的吗?它看起来几乎与您要求的完全一样。

    【讨论】:

    • 宾果游戏。非常适合我。
    【解决方案2】:

    您似乎想使用 Hibernate 中内置的 Criteria 查询 API。要执行上述查询,它看起来像这样:

    List<Stock> stocks = session.createCriteria(Stock.class)
        .add(Property.forName("id").eq(id))
        .list();
    

    如果您还没有访问 Hibernate Session 的权限,您可以像这样使用“DetachedCriteria”:

    DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class) 
        .add(Property.forName("id").eq(id));
    

    如果您想获取所有具有特定 ID 的 Bonus 股票,您可以执行以下操作:

    DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class)
         .createCriteria("Stock")
              .add(Property.forName("id").eq(id)));
    

    有关更多信息,请查看 Hibernate 文档中的 Criteria Queries

    【讨论】:

      【解决方案3】:

      @Sébastien Rocca-Serra

      select stock
      from com.something.Stock as stock, com.something.Bonus as bonus
      where stock.bonus.id = bonus.id
      

      这只是一个连接。 Hibernate 会自动执行此操作,当且仅当您设置了 StockBonus 之间的映射并且 bonusStock 的属性时。 Criteria.list() 将返回 Stock 对象,您只需调用 stock.getBonus()

      注意,如果你想做类似的事情

      select stock
      from com.something.Stock as stock
      where stock.bonus.value > 1000000
      

      您需要使用Criteria.createAlias()。应该是这样的

      session.createCriteria(Stock.class).createAlias("bonus", "b")
         .add(Restrictions.gt("b.value", 1000000)).list()
      

      【讨论】:

      • 感谢您的回复,我快接近了!但我正在尝试从 Bonus 表中选择属性 someValue 指向任何奖金的所有股票......
      【解决方案4】:

      @Sébastien Rocca-Serra
      现在我们正在取得具体的进展。您尝试执行的那种连接实际上无法通过 Criteria API 实现,但子查询应该完成同样的事情。首先为红利表创建一个DetachedCriteria,然后为someValue 使用IN 运算符。

      DetachedCriteria bonuses = DetachedCriteria.forClass(Bonus.class);
      List stocks = session.createCriteria(Stock.class)
          .add(Property.forName("someValue").in(bonuses)).list();
      

      这相当于

      select stock
      from com.something.Stock as stock
      where stock.someValue in (select bonus.id from com.something.Bonus as bonus)
      

      唯一的缺点是,如果您在 someValue 中引用了不同的表,并且您的 ID 在所有表中不是唯一的。但是您的查询也会遇到同样的缺陷。

      【讨论】:

      • 谢谢,这正是我所需要的。我在第一个条件的 id 字段上添加了一个投影: bonuses.setProjection(Property.forName("id"));是否需要/好的做法/不好的做法?为什么 ?再次感谢。
      【解决方案5】:

      Criteria API 不提供 HQL 中可用的所有功能。例如,您不能对同一列执行多个联接。

      为什么不使用 NAMED QUERIES?看起来更干净:

      Person person = session.getNamedQuery("Person.findByName")
                                   .setString(0, "Marcio")
                                   .list();
      

      【讨论】:

        【解决方案6】:

        我为 OMERO 编写了一个 GPL 解决方案,您可以轻松构建适合您情况的解决方案。

        用法:

        QueryBuilder qb = new QueryBuilder();
        qb.select("img");
        qb.from("Image", "img");
        qb.join("img.pixels", "pix", true, false);
        
        // Can't join anymore after this
        qb.where(); // First
        qb.append("(");
        qb.and("pt.details.creationTime > :time");
        qb.param("time", new Date());
        qb.append(")");
        qb.and("img.id in (:ids)");
        qb.paramList("ids", new HashSet());
        qb.order("img.id", true);
        qb.order("this.details.creationEvent.time", false);
        

        它充当状态机“select->from->join->where->order”等,并跟上可选参数。有几个 Criteria API 无法执行的查询(请参阅HHH-879),所以最后编写这个小类来包装 StringBuilder 会更简单。 (注意:有一张票 HHH-2407 描述了一个应该统一两者的 Hibernate 分支。之后,重新访问 Criteria API 可能是有意义的)

        【讨论】:

          【解决方案7】:

          查看hibernate-generic-dao 项目提供的搜索包。这是一个相当不错的 HQL Builder 实现。

          【讨论】:

            【解决方案8】:

            我知道这个帖子很老了,但我也在寻找一个 HqlBuilder 我找到了这个"screensaver" project
            它不是 Windows 屏幕保护程序,而是 “实验室信息管理系统 (LIMS),用于执行小分子和 RNAi 筛选的高通量筛选 (HTS) 设施。

            它包含一个看起来相当不错的 HQLBuilder。
            以下是可用方法的示例列表:

            ...
            HqlBuilder select(String alias);
            HqlBuilder select(String alias, String property);
            HqlBuilder from(Class<?> entityClass, String alias);
            HqlBuilder fromFetch(String joinAlias, String joinRelationship, String alias);
            HqlBuilder where(String alias, String property, Operator operator, Object value);
            HqlBuilder where(String alias, Operator operator, Object value);
            HqlBuilder where(String alias1, Operator operator, String alias2);
            HqlBuilder whereIn(String alias, String property, Set<?> values);
            HqlBuilder whereIn(String alias, Set<?> values);
            HqlBuilder where(Clause clause);
            HqlBuilder orderBy(String alias, String property);
            HqlBuilder orderBy(String alias, SortDirection sortDirection);
            HqlBuilder orderBy(String alias, String property, SortDirection sortDirection);
            String toHql();
            ...
            

            【讨论】:

              【解决方案9】:

              对于您的问题的类型安全方法,请考虑Querydsl

              示例查询变为

              HQLQuery query = new HibernateQuery(session);
              List<Stock> s = query.from(stock, bonus)
                .where(stock.someValue.eq(bonus.id))
                .list(stock);
              

              Querydsl 像 JPA2 一样使用 APT 进行代码生成,并支持 JPA/Hibernate、JDO、SQL 和 Java 集合。

              我是Querydsl的维护者,所以这个答案是有偏见的。

              【讨论】:

                【解决方案10】:

                对于另一个类型安全的查询 dsl,我推荐http://www.torpedoquery.org。该库还很年轻,但它通过直接使用实体的类来提供类型安全。这意味着在重构或重新设计之前查询不再适用时会出现早期编译器错误。

                我还为您提供了一个示例。我认为从您的帖子中您可以尝试进行子查询限制,因此我以此为基础:

                import static org.torpedoquery.jpa.Torpedo.*;
                
                Bonus bonus = from(Bonus.class);
                Query subQuery = select(bonus.getId());
                
                Stock stock = from(Stock.class);
                where(stock.getSomeValue()).in(subQuery);
                
                List<Stock> stocks = select(stock).list(entityManager);
                

                【讨论】:

                  【解决方案11】:

                  现在还可以使用标准的JPA Type Safe 查询和一个不太标准但也很好的Object Query

                  例子:

                  JPA 类型安全

                  EntityManager em = ...
                  CriteriaBuilder qb = em.getCriteriaBuilder();
                  CriteriaQuery<Stock> c = qb.createQuery(Stock.class);
                  Root<Stock> = c.from(Stock.class);
                  Predicate condition = qb.eq(p.get(Stock_.id), id);
                  c.where(condition);
                  TypedQuery<Stock> q = em.createQuery(c); 
                  List<Stock> result = q.getResultList();
                  

                  对象查询

                  EntityManager em = ...
                  ObjectQuery<Stock> query = new GenericObjectQuery<Stock>(Stock.class);
                  Stock toSearch = query.target();
                  query.eq(toSearch.getId(),id);
                  List<Stock> res = (List<Stock>)JPAObjectQuery.execute(query, em);
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2023-03-10
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-07-25
                    相关资源
                    最近更新 更多