【问题标题】:Hibernate Criteria Query to get specific columns休眠条件查询以获取特定列
【发布时间】:2012-07-22 12:41:29
【问题描述】:

我在我的代码中使用标准查询。它总是触发select * from ...

相反,我想忽略查询中的一列(字段),因为该字段有大量以字节为单位的数据。这会导致性能问题。

谁能给出一个想法?


一些更新

我在查询中添加了一个投影,它创建了一个类似...的查询

select
    this_.TEMPLATE_ID as y0_,
    this_.TEMPLATE_NAME as y1_,
    this_.CREATE_DATE as y2_,
    this_.UPDATE_DATE as y3_,
    this_.STATUS_CODE as y4_,
    this_.USER_ID as y5_,
    this_.UPDATED_BY as y6_,
    this_.CATEGORY_ID as y7_,
    this_.PRACTICE_ID as y8_ 
from
    templates this_ 
inner join
    user user1_ 
        on this_.USER_ID=user1_.USER_ID 
inner join
    template_categories category2_ 
        on this_.CATEGORY_ID=category2_.CATEGORY_ID 
where
    y4_=? 
    and y8_=? 
    and y5_ in (
        ?, ?
    ) 
order by
    y1_ asc limit ?

现在问题就像.. Unknown column 'y4_' in 'where clause' 和 y8_ 相同的错误, y5_ 意味着所有关闭它给出错误的地方。

我将其修改为 Query like ...

select
    this_.TEMPLATE_ID as y0_,
    this_.TEMPLATE_NAME as y1_,
    this_.CREATE_DATE as y2_,
    this_.UPDATE_DATE as y3_,
    this_.STATUS_CODE as y4_,
    this_.USER_ID as y5_,
    this_.UPDATED_BY as y6_,
    this_.CATEGORY_ID as y7_,
    this_.PRACTICE_ID as y8_ 
from
    templates this_ 
inner join
    user user1_ 
        on this_.USER_ID=user1_.USER_ID 
inner join
    template_categories category2_ 
        on this_.CATEGORY_ID=category2_.CATEGORY_ID 
where
    this_.STATUS_CODE=1
    and this_.PRACTICE_ID=1 
    and this_.USER_ID in (
        1, 2
    ) 
order by
    y1_ asc limit ?

它奏效了。但是不知道HQL怎么修改?

【问题讨论】:

    标签: java mysql hibernate hibernate-criteria


    【解决方案1】:

    您可以为此使用multiselect 函数。

       CriteriaBuilder cb=session.getCriteriaBuilder();
                CriteriaQuery<Object[]> cquery=cb.createQuery(Object[].class);
                Root<Car> root=cquery.from(User.class);
                cquery.multiselect(root.get("id"),root.get("Name"));
                Query<Object[]> q=session.createQuery(cquery);
                List<Object[]> list=q.getResultList();
                System.out.println("id        Name");
                for (Object[] objects : list) {
                    System.out.println(objects[0]+"        "+objects[1]);
                 }
                
    

    hibernate 5 支持此功能。createCriteria 在更高版本的 hibernate 中已弃用。所以你可以改用criteria builder

    【讨论】:

      【解决方案2】:

      我喜欢这种方法,因为它简单干净:

          String getCompaniesIdAndName = " select "
                  + " c.id as id, "
                  + " c.name as name "
                  + " from Company c ";
      
          @Query(value = getCompaniesWithoutAccount)
          Set<CompanyIdAndName> findAllIdAndName();
      
          public static interface CompanyIdAndName extends DTO {
              Integer getId();
      
              String getName();
      
          }
      

      【讨论】:

        【解决方案3】:

        您可以将 JPQL 以及 JPA Criteria API 用于任何类型的 DTO 投影(仅将选定的列映射到 DTO 类)。查看下面的代码 sn-ps 显示如何有选择地选择各种列而不是 选择所有列。这些示例还显示了如何从 加入多个列。我希望这有帮助 。

        JPQL 代码:

        String dtoProjection = "new com.katariasoft.technologies.jpaHibernate.college.data.dto.InstructorDto"
                        + "(i.id, i.name, i.fatherName, i.address, id.proofNo, "
                        + " v.vehicleNumber, v.vechicleType, s.name, s.fatherName, "
                        + " si.name, sv.vehicleNumber , svd.name) ";
        
                List<InstructorDto> instructors = queryExecutor.fetchListForJpqlQuery(
                        "select " + dtoProjection + " from Instructor i " + " join i.idProof id " + " join i.vehicles v "
                                + " join i.students s " + " join s.instructors si " + " join s.vehicles sv "
                                + " join sv.documents svd " + " where i.id > :id and svd.name in (:names) "
                                + " order by i.id , id.proofNo , v.vehicleNumber , si.name , sv.vehicleNumber , svd.name ",
                        CollectionUtils.mapOf("id", 2, "names", Arrays.asList("1", "2")), InstructorDto.class);
        
                if (Objects.nonNull(instructors))
                    instructors.forEach(i -> i.setName("Latest Update"));
        
                DataPrinters.listDataPrinter.accept(instructors);
        

        JPA 标准 API 代码:

        @Test
            public void fetchFullDataWithCriteria() {
                CriteriaBuilder cb = criteriaUtils.criteriaBuilder();
                CriteriaQuery<InstructorDto> cq = cb.createQuery(InstructorDto.class);
        
                // prepare from expressions
                Root<Instructor> root = cq.from(Instructor.class);
                Join<Instructor, IdProof> insIdProofJoin = root.join(Instructor_.idProof);
                Join<Instructor, Vehicle> insVehicleJoin = root.join(Instructor_.vehicles);
                Join<Instructor, Student> insStudentJoin = root.join(Instructor_.students);
                Join<Student, Instructor> studentInsJoin = insStudentJoin.join(Student_.instructors);
                Join<Student, Vehicle> studentVehicleJoin = insStudentJoin.join(Student_.vehicles);
                Join<Vehicle, Document> vehicleDocumentJoin = studentVehicleJoin.join(Vehicle_.documents);
        
                // prepare select expressions.
                CompoundSelection<InstructorDto> selection = cb.construct(InstructorDto.class, root.get(Instructor_.id),
                        root.get(Instructor_.name), root.get(Instructor_.fatherName), root.get(Instructor_.address),
                        insIdProofJoin.get(IdProof_.proofNo), insVehicleJoin.get(Vehicle_.vehicleNumber),
                        insVehicleJoin.get(Vehicle_.vechicleType), insStudentJoin.get(Student_.name),
                        insStudentJoin.get(Student_.fatherName), studentInsJoin.get(Instructor_.name),
                        studentVehicleJoin.get(Vehicle_.vehicleNumber), vehicleDocumentJoin.get(Document_.name));
        
                // prepare where expressions.
                Predicate instructorIdGreaterThan = cb.greaterThan(root.get(Instructor_.id), 2);
                Predicate documentNameIn = cb.in(vehicleDocumentJoin.get(Document_.name)).value("1").value("2");
                Predicate where = cb.and(instructorIdGreaterThan, documentNameIn);
        
                // prepare orderBy expressions.
                List<Order> orderBy = Arrays.asList(cb.asc(root.get(Instructor_.id)),
                        cb.asc(insIdProofJoin.get(IdProof_.proofNo)), cb.asc(insVehicleJoin.get(Vehicle_.vehicleNumber)),
                        cb.asc(studentInsJoin.get(Instructor_.name)), cb.asc(studentVehicleJoin.get(Vehicle_.vehicleNumber)),
                        cb.asc(vehicleDocumentJoin.get(Document_.name)));
        
                // prepare query
                cq.select(selection).where(where).orderBy(orderBy);
                DataPrinters.listDataPrinter.accept(queryExecutor.fetchListForCriteriaQuery(cq));
        
            }
        

        【讨论】:

          【解决方案4】:

          使用Projections 指定您要返回的列。

          示例

          SQL 查询

          SELECT user.id, user.name FROM user;
          

          休眠替代

          Criteria cr = session.createCriteria(User.class)
              .setProjection(Projections.projectionList()
                .add(Projections.property("id"), "id")
                .add(Projections.property("Name"), "Name"))
              .setResultTransformer(Transformers.aliasToBean(User.class));
          
            List<User> list = cr.list();
          

          【讨论】:

          • JPA 也可以做同样的事情吗?
          • @cingulata 是的,这是可能的。查看这篇文章objectdb.com/java/jpa/query/jpql/select
          • 我的投影属性为“null”。为什么?这与“别名”有关吗?
          【解决方案5】:

          您可以基于此类映射另一个实体(您应该使用实体名称来区分两者),第二个实体将是一种 dto(不要忘记 dto has design issues )。 您应该将第二个定义为只读并给它一个好名字,以明确这不是一个常规实体。 顺便说一句,只选择几列称为投影,所以用它来谷歌会更容易。

          替代方案 - 您可以使用您需要的字段列表创建命名查询(您将它们放在 select 中)或使用投影条件

          【讨论】:

            猜你喜欢
            • 2016-08-25
            • 1970-01-01
            • 2017-07-12
            • 1970-01-01
            • 2013-07-22
            • 1970-01-01
            • 2011-06-08
            相关资源
            最近更新 更多