我想问一下,我有可能为多个级别创建查询预测和标准吗? 我有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,姓名(Person),姓名(Wife)。 API我必须如何使用,我更喜欢使用Hibernate Criteria API。
这一次,我使用上面的代码来获取我的预期结果,但它会抛出异常并显示错误消息:
Exception in thread "main" org.hibernate.QueryException: could not resolve property: wife.name of: maladzan.model.Person
,
以及我的Restrictions.eq("wife.age", 19);
是否适合让有妻子19岁的人作为她的年龄值?
由于
答案 0 :(得分:6)
AFAIK使用aliastobean变压器不可能投射多个深度。你的选择是
选项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();
答案 1 :(得分:5)
我写了ResultTransformer
,这完全是这样做的。它的名称为AliasToBeanNestedResultTransformer
,请在github上查看。
答案 2 :(得分:1)
谢谢Sami Andoni。我能够使用您的AliasToBeanNestedResultTransformer进行微小修改以适应我的情况。我发现嵌套变换器不支持字段在超类中的场景,所以我对它进行了增强,以便在你预测的类的类继承层次结构中查找最多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;
...
}
答案 3 :(得分:-1)
而不是创建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();