复杂的Hibernate预测

我想问一下,有可能我创建了多个级别的查询预测和标准吗? 我有2个模型类:

@Entity @Table(name = "person") public class Person implements Serializable { @Id @GeneratedValue private int personID; private double valueDouble; private int valueInt; private String name; @OneToOne(cascade = {CascadeType.ALL}, orphanRemoval = true) @JoinColumn(name="wifeId") private Wife wife; /* * Setter Getter */ } @Entity @Table(name = "wife") public class Wife implements Serializable { @Id @GeneratedValue @Column(name="wifeId") private int id; @Column(name="name") private String name; @Column(name="age") private int age; /* * Setter Getter */ } 

我的标准API:

 ProjectionList projections = Projections.projectionList(); projections.add(Projections.property("this.personID"), "personID"); projections.add(Projections.property("this.wife"), "wife"); projections.add(Projections.property("this.wife.name"), "wife.name"); Criteria criteria = null; criteria = getHandlerSession().createCriteria(Person.class); criteria.createCriteria("wife", "wife", JoinType.LEFT.ordinal()); criterion = Restrictions.eq("wife.age", 19); criteria.add(criterion); criteria.setProjection(projections); criteria.setResultTransformer(Transformers.aliasToBean(Person.class)); return criteria.list(); 

我希望,我可以使用指定的wife属性条件查询Person,并指定返回resultSet。 所以我使用Projections获取指定的返回resultSet

我想要personID,姓名(人),姓名(妻子)将返回。 API我必须如何使用,我更喜欢使用Hibernate Criteria API。

这一次,我使用上面的代码获取我的预期结果,但是它会抛出exception并带有错误消息: Exception in thread "main" org.hibernate.QueryException: could not resolve property: wife.name of: maladzan.model.Person ,以及我的Restrictions.eq("wife.age", 19); 获得有19岁的妻子作为年龄值的人是否正确?

谢谢

AFAIK使用aliastobean变压器不可能投射多个深度。 你的选择是

  • 创建一个展平的数据传输对象(DTO)
  • 自己在内存中填充结果人
  • 实现自己的resulttransformer(类似于选项2)

选项1看起来像这样:

 Criteria criteria = getHandlerSession().createCriteria(Person.class) .createAlias("wife", "wife", JoinType.LEFT.ordinal()) .add(Restrictions.eq("wife.age", 19)); .setProjection(Projections.projectionList() .add(Projections.property("personID"), "personID") .add(Projections.property("name"), "personName") .add(Projections.property("wife.name"), "wifeName")); .setResultTransformer(Transformers.aliasToBean(PersonWifeDto.class)); return criteria.list(); 

我编写了ResultTransformer ,它完全是这样做的。 它的名字是AliasToBeanNestedResultTransformer ,请在github上查看。

谢谢Sami Andoni。 我能够使用您的AliasToBeanNestedResultTransformer进行微小修改以适应我的情况。 我发现嵌套变换器不支持字段在超类中的场景,因此我对它进行了增强,以便在您要投射到的类的类inheritance层次结构中查找最多10级深度的字段:

  public Object transformTuple(Object[] tuple, String[] aliases) { ... if (alias.contains(".")) { nestedAliases.add(alias); String[] sp = alias.split("\\."); String fieldName = sp[0]; String aliasName = sp[1]; Class subclass = getDeclaredFieldForClassOrSuperClasses(resultClass, fieldName, 1); ... } 

其中getDeclaredFieldForClassOrSuperClasses()定义如下:

 private Class getDeclaredFieldForClassOrSuperClasses(Class resultClass, String fieldName, int level) throws NoSuchFieldException{ Class result = null; try { result = resultClass.getDeclaredField(fieldName).getType(); } catch (NoSuchFieldException e) { if (level <= 10){ return getDeclaredFieldForClassOrSuperClasses( resultClass.getSuperclass(), fieldName, level++); } else { throw e; } } return result; } 

我对此嵌套属性的Hibernate投影如下所示:

 Projections.projectionList().add( Property.forName("metadata.copyright").as("productMetadata.copyright")); 

我投射的课程看起来像这样:

 public class ProductMetadata extends AbstractMetadata { ... } public abstract class AbstractMetadata { ... protected String copyright; ... } 

而不是创建Data Transfer Object (DTO)
projectionlist进行以下更改,它将适用于您。

  ProjectionList projections = Projections.projectionList(); projections.add(Projections.property("person.personID"), "personID"); projections.add(Projections.property("person.wife"), "wife"); projections.add(Projections.property("wife.name")); Criteria criteria = null; criteria = getHandlerSession().createCriteria(Person.class,"person").createAlias("person.wife", "wife"); criterion = Restrictions.eq("wife.age", 19); criteria.add(criterion); criteria.setProjection(projections); criteria.setResultTransformer(Transformers.aliasToBean(Person.class)); return criteria.list();