我有根实体Hostel及其单一关联User owner。
Hostel
User owner
当我获取Hostel实体时,我需要热切地获取User owner,但是只有它owner的3个属性:userId,firstName,lastName。
owner
现在,我的条件查询是:
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);
接下来,我criteria.list()得到了sql语句,该语句仅选择owner投影列表中指定的3个属性。但是它不会选择根Hostel实体的任何属性。生成的查询是:
criteria.list()
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为空的。五个映射是因为有五行Hostel匹配where条件。我创建了简单的sql查询,它工作正常,因此问题仅在这里。
Map
如何强制hibernate获取根Hostel实体的所有属性以及关联User owner实体的仅3个属性?
*我尝试使用 *EDIT ,getSessionFactory().getClassMetadata(Hostel.class)但它给出了有关在中映射枚举的错误Hostel。因此,我后退以Hostel手动列出属性。现在,我的条件查询是:
getSessionFactory().getClassMetadata(Hostel.class)
// 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); }
请注意,我删除了ALIAS_TO_ENTITY_MAP结果转换器。这产生了这样的mysql查询:
ALIAS_TO_ENTITY_MAP
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)
这个错误表示我没有Hostel在结果列表中输入文字hostels。我什至尝试用以下方法在结果列表“旅馆”中找出元素的类别:
hostels
List hostels = criteria.list(); System.out.println("firstRow.class=" + hostels.get(0).getClass());
它打印:
firstRow.class=class [Ljava.lang.Object;
然后,我尝试设置ALIAS_TO_ENTITY_MAP新的ProjectionList,但结果列表“旅馆”为:
[{}, {}, {}, {}, {}]
五张空的地图。五,因为db(table hostel)中有5行与where子句匹配。
然后我完全删除投影列表和hibernate检索5个旅馆和5个相关联的User ownerS和owner的图像作为预期。
问题是如何停止hibernate检索关联的关联Image实体User owner。最好的方法是仅获取3个相关联的道具User owner。
Image
谢谢!
您可以通过直接查询来做到这一点:
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_.firstname作为col_2_0_,user1_.lastname作为col_3_0_,hostel0_.id作为id1_0_,hostel0_.name作为name2_0_,…,hostel0_.owner_id作为user_id4_0_外部联接user1_.id = hostel0_.owner_id上的用户user1_
包含Hostel的所有字段,以及User的所有必填字段。
用获得的名单criteria.list()是List<Object[]>其行是 [ Hostel, Integer, String, String]
List<Object[]>
[ Hostel, Integer, String, String]
您可以使用来获取某些内容Criteria,但Criteria要比查询更严格。我找不到允许混合实体和字段的任何API。据我所知,不可能获得包含实体(旅馆)和与关联(owner.userId,owner.firstName,owner.lastName)分开的字段的行。
Criteria
我能想象的唯一方法是明确列出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 …)来实现一些自动化(注意:…):我使用别名投影只是为了以后可以使用包装器类,如果直接使用标量值,则可以安全地省略的Projection.alias:
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_中选择this_.id作为y0_,this_.name作为y1_,…,this_.user_id作为y3_,owner1_.id作为y4_,owner1_.firstname作为y5_,owner1_.lastname作为y6_,在this_上从外部加入用户owner1_ .user_id = owner1_.id
但是您将无法使用,criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)因为结果集不完全是来自字段的图像Hostel(即使没有别名)。实际上,列表是List<Object[]>带有行的,其中包含所有来自的单独字段,Hostel然后是来自的3个必填字段owner。
criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
您将需要添加一个包含a Hostel和3个其他字段的包装器类,以使用an AliasToBeanResultTransformer和获取true Hostel对象:
AliasToBeanResultTransformer
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();
我可以确认的是,当没有主人hostel.getOwner()是空的,当有一个,hostel.getOwner().getId()等于getOwner_id()和该访问不产生任何额外的查询。但是,任何访问的其他领域hostel.getOwner(),甚至firstName或lastName产生,因为一个User实体并没有在会议上加载。
hostel.getOwner()
hostel.getOwner().getId()
getOwner_id()
firstName
lastName
User
最常见的用法应该是:
for (HostelWrapper hostelw: criteria.list()) { Hostel hostel = hostelw.getHostel(); // use hostel, hostelw.getOwner_firstName and hostelw.getOwner_lastName }