java 复杂的休眠投影
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12105757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Complex Hibernate Projections
提问by Fauzi Achmad
I want to ask, it is possible that I create query projections and criterion for more than one level deep? I have 2 model classes:
我想问一下,我有可能为不止一个级别的深度创建查询投影和标准吗?我有 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
*/
}
My Criteria API :
我的标准 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();
and I hope, I can query Person, with specified criteria for wife property, and specified return resultSet. so i used Projections for getting specified return resultSet
我希望,我可以查询 Person,指定妻子属性的条件,并指定返回结果集。所以我使用 Projections 来获取指定的返回结果集
I want personID, name(Person), name(Wife) will returned. how API i must Use, i more prefer use Hibernate Criteria API.
我想要 personID, name(Person), name(Wife) 将返回。我必须如何使用 API,我更喜欢使用 Hibernate Criteria API。
This time, I used code above for getting my expected result, but it will throw Exception with error message :
Exception in thread "main" org.hibernate.QueryException: could not resolve property: wife.name of: maladzan.model.Person
,
and whether my Restrictions.eq("wife.age", 19);
is correct for getting person which has wife with 19 as her age value ?
这一次,我用上面得到我预期的结果代码,但它会抛出异常与错误消息:
Exception in thread "main" org.hibernate.QueryException: could not resolve property: wife.name of: maladzan.model.Person
和我是否Restrictions.eq("wife.age", 19);
是获得具有妻子19她的年龄价值的人是否正确?
Thanks
谢谢
回答by Firo
AFAIK it is not possible to project more than one level deep with aliastobean transformer. Your options are
AFAIK 不可能使用 aliastobean 转换器投射超过一层的深度。你的选择是
- create a flattened Data Transfer Object (DTO)
- fill the resulting Person in memory yourself
- implement your own resulttransformer (similar to option 2)
- 创建扁平化数据传输对象 (DTO)
- 自己在记忆中填充由此产生的 Person
- 实现您自己的 resulttransformer(类似于选项 2)
option 1 looks like this:
选项 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();
回答by Sami Andoni
回答by whitestryder
Thanks Sami Andoni. I was able to use your AliasToBeanNestedResultTransformer with a minor modification to suit my situation. What I found was that the nested transformer did not support the scenario where the field is in a super class so I enhanced it to look for fields up to 10 levels deep in the class inheritance hierarchy of the class you're projecting into:
谢谢萨米·安多尼。我能够使用您的 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);
...
}
Where getDeclaredFieldForClassOrSuperClasses() is defined as follows:
其中 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;
}
My Hibernate projection for this nested property looked like this:
我对此嵌套属性的 Hibernate 投影如下所示:
Projections.projectionList().add( Property.forName("metadata.copyright").as("productMetadata.copyright"));
and the class I am projecting into looks like this:
我正在投射的课程如下所示:
public class ProductMetadata extends AbstractMetadata {
...
}
public abstract class AbstractMetadata {
...
protected String copyright;
...
}
回答by Jubin Patel
Instead of creating Data Transfer Object (DTO)
In projectionlist
make below changes and it will work for you.
而不是创建Data Transfer Object (DTO)
In projectionlist
make 下面的更改,它将为您工作。
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();