您可以通过直接查询来做到这一点:
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]
您可以使用来获取某些内容
Criteria,但
Criteria要比查询更严格。我找不到允许混合实体和字段的任何API。据我所知,不可能获得包含实体(旅馆)和与关联(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
…)来实现一些自动化(注意:…):我使用别名投影只是为了以后可以使用包装器类,如果直接使用标量值,则可以安全地省略的
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。
您将需要添加一个包含a
Hostel和3个其他字段的包装器类,以使用an
AliasToBeanResultTransformer和获取true
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();
我可以确认的是,当没有主人
hostel.getOwner()是空的,当有一个,
hostel.getOwner().getId()等于
getOwner_id()和该访问不产生任何额外的查询。但是,任何访问的其他领域
hostel.getOwner(),甚至
firstName或
lastName产生,因为一个
User实体并没有在会议上加载。
最常见的用法应该是:
for (HostelWrapper hostelw: criteria.list()) { Hostel hostel = hostelw.getHostel(); // use hostel, hostelw.getOwner_firstName and hostelw.getOwner_lastName}


