复杂的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();