如何在hibernate 4中使用限制进行关联获取?

时间:2014-08-15 18:26:47

标签: java hibernate hibernate-criteria

我有根实体Hostel及其单一关联User owner

当我提取Hostel实体时,我需要急切地提取User owner,但只需提取所有者的3个属性:userIdfirstNamelastName

此外,在此查询中,我无需获取User owner的某些关联。它们是:avatarimages User实体。

现在我的标准查询是:

@SuppressWarnings("unchecked")
    public void findHostelBy(HostelSearch hs) {
        Criteria criteria = currenSession().createCriteria(Hostel.class);

        String country = hs.getCountry();

        criteria.add(Restrictions.ge("endDate", Calendar.getInstance()));
        if (StringUtils.notNullAndEmpty(country)) {
            criteria.add(Restrictions.eq("country", country));
        }

        // making Hostel's associations lazy
        criteria.setFetchMode("images", FetchMode.SELECT);
        criteria.setFetchMode("requests", FetchMode.SELECT);
        criteria.setFetchMode("feedbacks", FetchMode.SELECT);

        criteria.setReadOnly(true);
        criteria.addOrder(Order.desc("rating"));

        // retrieve owner association
        criteria = criteria
                .createAlias("owner","owner",JoinType.LEFT_OUTER_JOIN)
                .setProjection(
                        Projections.projectionList()
                                .add(Projections.property("owner.userId"))
                                .add(Projections.property("owner.firstName"))
                                .add(Projections.property("owner.lastName")))
                .setFetchMode("owner.avatar", FetchMode.SELECT)
                .setFetchMode("owner.images", FetchMode.SELECT);

        Long count = (Long) criteria
                .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                .setProjection(Projections.rowCount()).uniqueResult();

        criteria.setProjection(null);

        List<Hostel> hostels = criteria.list();

        for (Hostel hostel : hostels) {
            User owner = hostel.getOwner();
            System.out.println("owner=" + owner);
        }           
    }

// retrieve owner association评论之后,我提取User owner关联。我通过以下方式将owner的选择限制为3个属性:

Projections.projectionList()
                                .add(Projections.property("owner.userId"))
                                .add(Projections.property("owner.firstName"))
                                .add(Projections.property("owner.lastName")))

然后我让所有者的协会头像和图像变得懒惰:

.setFetchMode("owner.avatar", FetchMode.SELECT)
.setFetchMode("owner.images", FetchMode.SELECT);

我在线上获得例外

List<Hostel> hostels = criteria.list();

例外是:

Caused by: org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.home.hostme.entity.Image. Expected: class java.lang.Long, got class java.lang.Integer
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:134)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)
    at org.hibernate.type.EntityType.resolve(EntityType.java:490)
    at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:168)
    at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:137)
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1107)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:963)
    at org.hibernate.loader.Loader.doQuery(Loader.java:910)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
    at org.hibernate.loader.Loader.doList(Loader.java:2522)
    at org.hibernate.loader.Loader.doList(Loader.java:2508)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2338)
    at org.hibernate.loader.Loader.list(Loader.java:2333)
    at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:124)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1662)
    at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:374)
    at com.home.hostme.dao.impl.HostelDaoImpl.findHostelBy(HostelDaoImpl.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    ... 51 more

Hostel实体的主键列是Integer,但Image实体的主键是Long。但我不想急切地从avatar检索imagesUser owner,而是我描述了它。

如何将我的查询更新为从avatar关联延迟抓取imagesUser owner

此查询从User owner关联中提取所有属性,因此我的限制也不起作用。

P.S。如果我没有获取User owner关联,那么一切正常。

1 个答案:

答案 0 :(得分:0)

这不是你如何指导Hibernate关于LAZY的获取:

.setFetchMode("owner.avatar", FetchMode.SELECT)

FetchMode.SELECT用于在单独的选择

中检索关联的信息

对于LAZY,你应该设置:

.setFetchMode("owner.avatar", FetchMode.LAZY)

还有很多我真正无法获得的东西,比如:

  1. 为什么要创建投影来获取计数:

    Long count = (Long) criteria
            .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
            .setProjection(Projections.rowCount()).uniqueResult();
    
  2. 然后将投影设置为空

    criteria.setProjection(null);
    
  3. 如果您想要一个拥有所有者但没有任何其他关联的旅馆列表,您只需标记以下内容:

    .setFetchMode("owner.avatar", FetchMode.LAZY)
    

    另一个选择是让所有关联LAZY并简单地指示在查询的基础上获取什么:

    select h
    from Hostel h
    left join fetch h.owner o
    

    虽然h.owner.avatar和h.owner.images有意义不被提取,但h.owner.hostel是实际的宿舍参考,Hibernate不会为这两个发布新的连接。它知道如何处理单个连接的双向关联。