当前位置: 首页 > 知识库问答 >
问题:

如何使HIberNate获取根实体的所有属性,而只获取关联实体的特定属性?

郭皓
2023-03-14

我有根实体旅馆及其单个关联用户所有者

当我获取Hotel实体时,我需要急切地获取用户所有者,但只有所有者的3个属性:userId、afstName、lastName。

现在我的标准查询是:

Criteria criteria = currenSession().createCriteria(Hostel.class);

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

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

criteria.setFetchMode("owner", FetchMode.SELECT);
criteria.addOrder(Order.desc("rating"));

// needed to reset previous rowCount projection
criteria.setProjection(null);

// retrieve owner association
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")));

criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);

接下来,我执行标准。list(),我得到了sql语句,它只选择了投影列表中指定的owner的3个属性。但它不选择根<code>Hostel</code>实体的任何属性。生成的查询为:

select
    owner1_.user_id as y0_,
    owner1_.firstName as y1_,
    owner1_.lastName as y2_ 
from
    HOSTEL this_ 
left outer join
    USER owner1_ 
        on this_.owner_fk=owner1_.user_id 
where
    this_.end_date>=? 
    and this_.country=?        
order by
    this_.rating desc limit ?

此查询不起作用,因为它返回五个空的Map。五个映射是因为有五个<code>Hostel</code>行符合where条件。我创建了一个简单的sql查询,它工作得很好,所以问题只在这里。

如何强制Hibernate以获取rootHotel实体的所有属性,而只有3个属性的已分类用户所有者实体?

编辑我尝试使用getSessionFactory().getClassMetadata(Hostel.class),但它给出了有关在Hostel中映射枚举的错误。所以我回退到手动列出旅馆属性。目前,我的条件查询是:

// retrieve owner association
        criteria.createAlias("owner", "owner", JoinType.LEFT_OUTER_JOIN);
        criteria.setProjection(Projections.projectionList()
                .add(Projections.property("hostelId"))
                .add(Projections.property("address"))
                .add(Projections.property("country"))
                .add(Projections.property("region"))
                .add(Projections.property("gender"))
                .add(Projections.property("owner.userId"))
                .add(Projections.property("owner.firstName"))
                .add(Projections.property("owner.lastName")));

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

for (Hostel hostel : hostels) { // at this line I get error java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.home.hostme.entity.Hostel
            User owner = hostel.getOwner();
            System.out.println("owner=" + owner);
        }

请注意,我移除了< code>ALIAS_TO_ENTITY_MAP结果转换器。这生成了这样的mysql查询:

select
    this_.hostel_id as y0_,
    this_.address as y1_,
    this_.country as y2_,
    this_.region as y3_,
    this_.gender as y4_,
    owner1_.user_id as y5_,
    owner1_.firstName as y6_,
    owner1_.lastName as y7_ 
from
    HOSTEL this_ 
left outer join
    USER owner1_ 
        on this_.owner_fk=owner1_.user_id 
where
    this_.end_date>=? 
    and this_.country=? 
order by
    this_.rating desc limit ?

在for-each循环中得到这样一个错误:

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.home.hostme.entity.Hostel
    at com.home.hostme.dao.impl.HostelDaoImpl.findHostelBy(HostelDaoImpl.java:168)
    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)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy64.findHostelBy(Unknown Source)
    at com.home.hostme.service.HostelService.findHostelBy(HostelService.java:27)
    at com.home.hostme.service.HostelService$$FastClassByCGLIB$$74db5b21.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    at com.home.hostme.service.HostelService$$EnhancerByCGLIB$$7af3bc10.findHostelBy(<generated>)
    at com.home.hostme.web.hostel.HostelController.doSearch(HostelController.java:94)
    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.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

此错误意味着我在结果列表中没有旅馆类型。我什至试图找出结果列表“旅馆”中的元素类:

List hostels = criteria.list();
        System.out.println("firstRow.class=" + hostels.get(0).getClass());

它打印了:

firstRow.class=class [Ljava.lang.Object;

然后,我尝试设置ALIAS_TO_ENTITY_MAP为新的项目列表,但结果列表'旅馆'是:

[{}, {}, {}, {}, {}]

五张空地图。五行,因为db(table hostel)中有5行匹配where子句。

然后我完全删除了投影列表,Hibernate按预期检索了5个主机和5个相关的用户所有者所有者的图像。

问题是如何停止Hibernate检索关联用户所有者的关联图像实体。最好的办法是只获取关联用户所有者的 3 个特定道具。

谢谢!

共有3个答案

暨成双
2023-03-14

据我观察,你不可能得到你想要的结果。

我们可以使用以下步骤完成:

String[] propertyNames = sessionFactory.getClassMetadata(Hostel.class).getPropertyNames();

ProjectionList projectionList = Projections.projectionList();

for (String propString : propertyNames) {
                projectionList.add(Projections.property(propString));
}

请按以下方式更改代码

criteria.createAlias("owner", "owner", JoinType.LEFT_OUTER_JOIN)
        .setProjection(
                projectionList
                        .add(Projections.property("owner.userId"))
                        .add(Projections.property("owner.firstName"))
                        .add(Projections.property("owner.lastName")));

请试着知道。

宦博雅
2023-03-14

@Serge Ballesta解决了我的问题,但这是我的最终工作代码:

Criteria criteria = currenSession().createCriteria(Hostel.class);
criteria.add(Restrictions.ge("endDate", Calendar.getInstance()));
        if (StringUtils.notNullAndEmpty(country)) {
            criteria.add(Restrictions.eq("country", country));
        }
Long count = (Long) criteria
                .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
                .setProjection(Projections.rowCount()).uniqueResult();

// mark query as readonly
        criteria.setReadOnly(true);
        // descendingly sort result by rating property of Hostel entity
        criteria.addOrder(Order.desc("rating"));
        // reset rowCount() projection
        criteria.setProjection(null);

ProjectionList hostelProjList = Projections.projectionList();
        ClassMetadata hostelMetadata = getSessionFactory().getClassMetadata(
                Hostel.class);
        // add primary key property - hostelId
        hostelProjList.add(Projections.property(hostelMetadata
                .getIdentifierPropertyName()), "hostelId");
        // add all normal properties of Hostel entity to retrieve from db
        for (String prop : hostelMetadata.getPropertyNames()) {
            //skip associations
            if (!prop.equals("owner") && !prop.equals("images")
                    && !prop.equals("requests") && !prop.equals("feedbacks"))
                hostelProjList.add(Projections.property(prop), prop);
        }
        // add properties of User owner association to be retrieved
        hostelProjList
                .add(Projections.property("owner.userId"), "owner_id")
                .add(Projections.property("owner.firstName"), "owner_firstName")
                .add(Projections.property("owner.lastName"), "owner_lastName");

        // create alias to retrieve props of User owner association
        criteria.createAlias("owner", "owner", JoinType.LEFT_OUTER_JOIN);
        criteria.setProjection(hostelProjList);

        criteria.setResultTransformer(new AliasToBeanResultTransformer(
                HostelWrapper.class));

List<HostelWrapper> wrappers = criteria.list();

我的< code>HostelWrapper是:

public class HostelWrapper {
    private Hostel hostel;
    private int owner_id;
    private String owner_firstName;
    private String owner_lastName;

    public HostelWrapper() {
        hostel = new Hostel();
    }

    public Hostel getHostel() {
        return hostel;
    }

    public void setHostelId(Integer hostelId) {
        this.hostel.setHostelId(hostelId);
    }

public void setCountry(String country) {
        this.hostel.setCountry(country);
    }
public int getOwner_id() {
        return owner_id;
    }

    public void setOwner_id(Integer owner_id) {
        this.owner_id = owner_id == null ? 0 : owner_id;
    }

    public String getOwner_firstName() {
        return owner_firstName;
    }

    public void setOwner_firstName(String owner_firstName) {
        this.owner_firstName = owner_firstName;
    }

    public String getOwner_lastName() {
        return owner_lastName;
    }

    public void setOwner_lastName(String owner_lastName) {
        this.owner_lastName = owner_lastName;
    }

< code > aliastobeenresulttransformer 使用此< code>HostelWrapper将hibernate结果集映射到实体。

我最后的结论是,当你想设定联想的投影时,HQL是正确的选择。使用< code > aliastobeenresulttransformer ,您可以绑定到属性名称,使用hql也是一样。好处是HQL更容易写。

艾修然
2023-03-14

您可以通过直接查询来做到这一点:

Query query = session.createQuery("SELECT hostel, owner.id, owner.firstname, "
        +"owner.lastname FROM Hostel hostel LEFT OUTER JOIN hostel.ower AS owner");
List list = query.list();

生成如下SQL语句:

选择hostel0。id为col_0_0_,user1_。id为col_1_0_,user1_。名为col_2_0_,user1_。姓col_3_0,hostel0。id为id1_0_,hostel0_。名称为name2_0_,…,hostel0_。Hostel hostel0_的owner_id作为user_id4_0_左外侧加入user1_上的用户user1_。id=hostel0_.owner_id

包含旅馆的所有字段,只有用户的必填字段。

使用条件获得的列表。list()是一个列表

您可以使用Criteria获得一些信息,但Criteria比查询更严格。我找不到任何允许混合实体和字段的API。因此,据我所知,不可能获取包含实体(Hostels)的行以及与关联(owner.userId、owner.firstName、owner.lastName)分开的字段。

我可以想象的唯一方法是明确列出Hostels的所有字段:

criteria.createAlias("owner", "owner", JoinType.LEFT_OUTER_JOIN)
    .setProjection(
            Projections.projectionList()
                    .add(Projections.property("hostelId"))
                    .add(Projections.property("country"))
                    .add(Projections.property("endDate"))
                    ...
                    ... all other properties from Hostel
                    ...
                    .add(Projections.property("owner.userId"))
                    .add(Projections.property("owner.firstName"))
                    .add(Projections.property("owner.lastName")));

您可以通过使用元数据(不要忘记id...)-注意:我使用别名投影只是为了以后能够使用包装类,如果您直接使用标量值,可以安全地省略< code>Projection.alias:

    ProjectionList hostelProj = Projections.projectionList();
    String id = sessionFactory.getClassMetadata(Hostel.class)
            .getIdentifierPropertyName();
    hostelProperties.add(Projections.alias(Projections.property(id),id));
    for (String prop: sessionFactory.getClassMetadata(Hostel.class).getPropertyNames()) {
        hostelProperties.add(Projections.alias(Projections.property(prop), prop));
    }
    Criteria criteria = session.createCriteria(Hostel.class);
    criteria.createAlias("owner", "owner", JoinType.LEFT_OUTER_JOIN);
    criteria.setProjection(
            Projections.projectionList()
                    .add(hostelProj)
                    .add(Projections.property("owner.id"))
                    .add(Projections.property("owner.firstName"))
                    .add(Projections.property("owner.lastName")));
    List list = criteria.list();

这样才能正确地生成

选择this_。id为y0_,this_。名称为y1_,…,this_。user_id为y3_,owner_。id为y4_,所有者1_。名为y5_,所有者__。姓y6_来自酒店this_left外部加入用户owner1_在this_.user_id=owner1.id

但是您将无法使用 criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP),因为结果集并不完全是 Hostel 中字段的图像(即使没有别名)。事实上,列表是一个列表

您必须添加一个包含< code>Hostel和其他3个字段的包装类,才能使用< code > aliastobeenresulttransformer 并获得真正的< code>Hostel对象:

public class HostelWrapper {
    private Hostel hostel;
    private int owner_id;
    private String owner_firstName;
    private String owner_lastName;

    public HostelWrapper() {
        hostel = new Hostel();
    }

    public Hostel getHostel() {
        return hostel;
    }
    public void setId(int id) {
        hostel.setId(id);
    }
    public void setOwner(User owner) {
        hostel.setOwner(owner);
    }
    // other setters for Hostel fields ...

    public int getOwner_id() {
        return owner_id;
    }
    public void setOwner_id(Integer owner_id) {
    // beware : may be null because of outer join
        this.owner_id = (owner_id == null) ? 0 : owner_id;
    }
    //getters and setters for firstName and lastName ...
}

然后您可以成功编写:

criteria.setResultTransformer(new AliasToBeanResultTransformer(HostelWrapper.class));
List<HostelWrapper> hostels = criteria.list();

Hostel hostel = hostels.get(0).getHostel();
String firstName = hostels.get(0).getFirstName();

我可以验证当没有所有者时< code>hostel.getOwner()为空,当有所有者时,< code>hostel.getOwner()为空。getId()等于< code>getOwner_id(),并且该访问不会生成任何额外的查询。但是对< code>hostel.getOwner()的其他字段的任何访问,甚至是< code>firstName或< code>lastName都会生成一个,因为< code>User实体没有在会话中加载。

最常见的用法应该是:

for (HostelWrapper hostelw: criteria.list()) {
    Hostel hostel = hostelw.getHostel();
    // use hostel, hostelw.getOwner_firstName and hostelw.getOwner_lastName
}
 类似资料:
  • 问题内容: 我有根实体及其单一关联。 当我获取实体时,我需要热切地获取,但是只有它的3个属性:userId,firstName,lastName。 现在,我的条件查询是: 接下来,我得到了sql语句,该语句仅选择投影列表中指定的3个属性。但是它不会选择根实体的任何属性。生成的查询是: 该查询不起作用,因为它返回了五个为空的。五个映射是因为有五行匹配where条件。我创建了简单的sql查询,它工作正

  • 问题内容: 我有一个具有多个属性的核心数据实体,并且想要一个属性中所有对象的列表。我的代码如下所示: 但这给了我一个NSException错误,我不知道为什么,或者我应该怎么做。我已经阅读了NSFetchRequest类的描述,但从中讲不出来。 任何建议,将不胜感激。 编辑:从Bluehound获得提示后,我将代码更改为: 运行时错误消失了,但我仍然不知道它是否有效,因为我不确定如何将列表转换为字

  • 我有两个实体与单向@OneTo多项映射: 我想获得所有B实体的列表,它们是匹配限制的A实体的子实体。 这就是我卡住的地方:c.list()将返回给我一个对象列表。我不关心A,我想要B。我如何使用Hibernate标准/预测来完成它?如果有关系,我使用Hibernate 4.2.12 在这种简化的情况下,只是急切地去拿是有意义的;在真实的例子中,有一个由四个一对一的单向关联组成的链,我想让所有(或者

  • 我有一个本体,是使用Protegé4.3.0创建的,我将使用OWL-API为指定的个体和对象属性表达式获取对象属性值(即一组对象)。

  • 我使用的是“1.7.0_79”版本。获取以下异常 数据\成员\密钥失败:java。例外:太阳。反映无法将GeneratedSerializationConstructorAccessor1强制转换为sun。反映sun上的SerializationConstructorAccessorImpl。反映MethodAccessorGenerator。generateSerializationConstr

  • 关联实体和关联关系属性有什么区别?在我的一本名为《现代数据库管理》(Hoffer,第11版)的书中,作者陈述了两者之间的区别。然而,它并没有真正解释为什么会有差别,相反,它只是给出了它们是如何不同的例子。 据我所知,一个有一个属性关联的关系是一个关联关系属性,并用一条虚线表示一个圆角矩形,该矩形内有该属性。而关联实体是描述关系的多个属性。两者都只能用于ER图解中的多对多关系。我的思维过程正确吗?