Java 在Hibernate中使用Transformers.aliasToBean填充子bean
我有下面两种豆子:Java 在Hibernate中使用Transformers.aliasToBean填充子bean,java,hibernate,Java,Hibernate,我有下面两种豆子: Address { String name; String number; String zipcode; String town; } MyEntity { Address address; String value1; String value2; } 我正在尝试执行下一个Hibernate查询: private final List<String> propertiesDistinct = Arra
Address {
String name;
String number;
String zipcode;
String town;
}
MyEntity {
Address address;
String value1;
String value2;
}
我正在尝试执行下一个Hibernate查询:
private final List<String> propertiesDistinct = Arrays.asList("address.name");
private final List<String> properties = Arrays.asList("address.number",
"address.zipcode", "address.town")
ProjectionList projectionList = Projections.projectionList();
if (propertiesDistinct != null) {
ProjectionList projectionListDistinct = Projections.projectionList();
for (String propertyDistinct : propertiesDistinct)
projectionListDistinct.add(Projections.property(propertyDistinct).as(propertyDistinct));
projectionList.add(Projections.distinct(projectionListAgrupar));
}
if (properties != null)
for (String property : properties)
projectionList.add(Projections.property(property).as(property));
criterio.setProjection(projectionList);
// MORE FILTERS ON MyEntity FIELDS
//... criterio.add(Restrinctions...);
// I want to recover the results on my bean MyEntity so I don't have to create a new one
criterio.setResultTransformer(Transformers.aliasToBean(MyEntity.class));
我知道Hibernate正在寻找类似于:
public String getAddressName() {} // This should be in MyEntity
而不是:
public String getName() {} // In my Address bean
如何在不创建新bean的情况下修复此问题
谢谢 尝试创建一个别名,如
criterio.createAlias(“地址”、“添加”)
然后编辑属性,使其类似于Arrays.asList(“add.number”、“add.zipcode”、“add.town”)
希望这有帮助。我写了一个ResultTransformer,可以解决您的问题。它的名称是AliasToBeanNestedResultTransformer,请在上查看。works fine中提供的代码,但对于新版本的hibernate,
导入中有更改。具体如下
org.hibernate.property.PropertyAccessor
替换为org.hibernate.property.access.spi.PropertyAccess
及
org.hibernate.property.PropertyAccessorFactory
替换为org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl
因此,您必须从更改代码
PropertyAccessor accessor = PropertyAccessorFactory.getPropertyAccessor("property");
accessor.getSetter(resultClass, (String)subclassToAlias.get(subclass).get(2)).set(root, subObject, null);
到
AliasToBeanNestedResultTransformer不处理嵌套的多级DTO,所以我重写了一个处理n级DTO的
希望这有帮助
public class AliasToBeanNestedMultiLevelResultTransformer extends AliasedTupleSubsetResultTransformer {
private static final long serialVersionUID = -8047276133980128266L;
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
private boolean initialized;
private Class<?> resultClass;
private Map<String,Class<?>> clazzMap = new HashMap<>();
private Map<String,Setter> settersMap = new HashMap<>();
public AliasToBeanNestedMultiLevelResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
public Object transformTuple(Object[] tuples, String[] aliases) {
Map<String,Object> nestedObjectsMap = new HashMap<>();
Object result;
try {
result = resultClass.newInstance();
if (!initialized){
initialized = true;
initialize(aliases);
}
for (int a=0;a<aliases.length;a++){
String alias = aliases[a];
Object tuple = tuples[a];
Object baseObject = result;
int index = alias.lastIndexOf(".");
if(index>0){
String basePath = alias.substring(0, index);
baseObject = nestedObjectsMap.get(basePath);
if (baseObject == null){
baseObject = clazzMap.get(basePath).newInstance();
nestedObjectsMap.put(basePath, baseObject);
}
}
settersMap.get(alias).set(baseObject, tuple,null);
}
for (Entry<String,Object> entry:nestedObjectsMap.entrySet()){
Setter setter = settersMap.get(entry.getKey());
if (entry.getKey().contains(".")){
int index = entry.getKey().lastIndexOf(".");
String basePath = entry.getKey().substring(0, index);
Object obj = nestedObjectsMap.get(basePath);
setter.set(obj, entry.getValue(), null);
}
else{
setter.set(result, entry.getValue(), null);
}
}
}catch ( InstantiationException | IllegalAccessException e) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
return result;
}
private void initialize(String[] aliases) {
PropertyAccessor propertyAccessor = new ChainedPropertyAccessor(
new PropertyAccessor[] {
PropertyAccessorFactory.getPropertyAccessor( resultClass, null ),
PropertyAccessorFactory.getPropertyAccessor( "field" )
}
);
for (int a=0;a<aliases.length;a++){
String alias = aliases[a];
Class<?> baseClass = resultClass;
if (alias.contains(".")){
String[] split = alias.split("\\.");
StringBuffer res = new StringBuffer();
for (int i=0;i<split.length;i++){
if (res.length()>0) res.append(".");
String item = split[i];
res.append(item);
String resString = res.toString();
if (i==split.length-1){
clazzMap.put(resString,baseClass);
settersMap.put(resString, propertyAccessor.getSetter(baseClass, item));
break;
}
Class<?> clazz = clazzMap.get(resString);
if (clazz==null){
clazz = propertyAccessor.getGetter(baseClass,item).getReturnType();
settersMap.put(resString, propertyAccessor.getSetter(baseClass, item));
clazzMap.put(resString,clazz);
}
baseClass = clazz;
}
}
else{
clazzMap.put(alias, resultClass);
settersMap.put(alias, propertyAccessor.getSetter(resultClass, alias));
}
}
}
公共类别名ToBeanNestedMultilevelResultTransformer扩展了别名TupleSubstreSultTransformer{
私有静态最终长serialVersionUID=-8047276133980128266L;
公共布尔值isTransformedValueATupleElement(字符串[]别名,int-tupleLength){
返回false;
}
私有布尔初始化;
私有类resultClass;
私有映射基类=resultClass;
if(别名为.contains(“.”){
String[]split=alias.split(“\\”);
StringBuffer res=新的StringBuffer();
对于(inti=0;i0)res.append(“.”);
字符串项=拆分[i];
附加(项目)决议;
字符串resString=res.toString();
如果(i==split.length-1){
clazzMap.put(resString,基类);
settersMap.put(resString,propertyAccessor.getSetter(基类,项));
打破
}
Class clazz=clazzMap.get(resString);
if(clazz==null){
clazz=propertyAccessor.getGetter(基类,项).getReturnType();
settersMap.put(resString,propertyAccessor.getSetter(基类,项));
clazzMap.put(resString,clazz);
}
baseClass=clazz;
}
}
否则{
clazzMap.put(别名,resultClass);
setterMap.put(别名,propertyAccessor.getSetter(resultClass,别名));
}
}
}
}我的解决方案非常基本。它不像一个合适的结果转换器那样干净,但是当您只需要对一些属性进行快速投影时,它非常有用
如果您获得,则无法在com.entities.MyEntity类上找到address.name的setter
这并不意味着Hibernate正在寻找公共字符串getAddressName(){}
。相反,它寻找一个具有不可能的“setAddress.name”名称的setter
代替.add(Projections.property(“address.name”),“address.name”))
键入一个合适的setter名称作为.add()方法的第二个参数,如下.add(Projections.property(“address.name”),“address.name”)
然后,只需在“MyEntity”根对象上添加一个setter:“setAddressName”
缺点是它会用额外的方法“弄脏”对象
也已发布。您在MyEntity中有setAddress(Address Address)吗?在所有Bean中有所有其他setter吗?@bellabax是的,我有:)我尝试了您的解决方案,但遇到了下一个异常:org.hibernate.QueryException:无法直接在组件上创建Criteria对象。在拥有的实体上创建条件,并使用虚线属性访问组件属性:address
尝试createCriteria
而不是createAlias
。我无法测试我自己。你是否将你的预测添加到新的标准中?请注意,createCriteria
返回Criteria
的实例。你应该把你的计划设置成这个新的。谢谢你的帮助,我把它交给了萨米·安多尼·transformer。谢谢你抽出时间:)萨米·安多尼这正是我想要的!非常感谢你。伟大的变形金刚:)@Sami Andoni:你能给我一些关于收集(OneToMany关系)的指南吗?你可以在Object tuple=tuples[a]之后添加;如果(tuple==null)继续;
PropertyAccess propertyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess(resultClass, (String)subclassToAlias.get(subclass).get(2));
propertyAccess.getSetter().set(root, subObject, null);
public class AliasToBeanNestedMultiLevelResultTransformer extends AliasedTupleSubsetResultTransformer {
private static final long serialVersionUID = -8047276133980128266L;
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
private boolean initialized;
private Class<?> resultClass;
private Map<String,Class<?>> clazzMap = new HashMap<>();
private Map<String,Setter> settersMap = new HashMap<>();
public AliasToBeanNestedMultiLevelResultTransformer(Class<?> resultClass) {
this.resultClass = resultClass;
}
public Object transformTuple(Object[] tuples, String[] aliases) {
Map<String,Object> nestedObjectsMap = new HashMap<>();
Object result;
try {
result = resultClass.newInstance();
if (!initialized){
initialized = true;
initialize(aliases);
}
for (int a=0;a<aliases.length;a++){
String alias = aliases[a];
Object tuple = tuples[a];
Object baseObject = result;
int index = alias.lastIndexOf(".");
if(index>0){
String basePath = alias.substring(0, index);
baseObject = nestedObjectsMap.get(basePath);
if (baseObject == null){
baseObject = clazzMap.get(basePath).newInstance();
nestedObjectsMap.put(basePath, baseObject);
}
}
settersMap.get(alias).set(baseObject, tuple,null);
}
for (Entry<String,Object> entry:nestedObjectsMap.entrySet()){
Setter setter = settersMap.get(entry.getKey());
if (entry.getKey().contains(".")){
int index = entry.getKey().lastIndexOf(".");
String basePath = entry.getKey().substring(0, index);
Object obj = nestedObjectsMap.get(basePath);
setter.set(obj, entry.getValue(), null);
}
else{
setter.set(result, entry.getValue(), null);
}
}
}catch ( InstantiationException | IllegalAccessException e) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
return result;
}
private void initialize(String[] aliases) {
PropertyAccessor propertyAccessor = new ChainedPropertyAccessor(
new PropertyAccessor[] {
PropertyAccessorFactory.getPropertyAccessor( resultClass, null ),
PropertyAccessorFactory.getPropertyAccessor( "field" )
}
);
for (int a=0;a<aliases.length;a++){
String alias = aliases[a];
Class<?> baseClass = resultClass;
if (alias.contains(".")){
String[] split = alias.split("\\.");
StringBuffer res = new StringBuffer();
for (int i=0;i<split.length;i++){
if (res.length()>0) res.append(".");
String item = split[i];
res.append(item);
String resString = res.toString();
if (i==split.length-1){
clazzMap.put(resString,baseClass);
settersMap.put(resString, propertyAccessor.getSetter(baseClass, item));
break;
}
Class<?> clazz = clazzMap.get(resString);
if (clazz==null){
clazz = propertyAccessor.getGetter(baseClass,item).getReturnType();
settersMap.put(resString, propertyAccessor.getSetter(baseClass, item));
clazzMap.put(resString,clazz);
}
baseClass = clazz;
}
}
else{
clazzMap.put(alias, resultClass);
settersMap.put(alias, propertyAccessor.getSetter(resultClass, alias));
}
}
}
public void setAddressName(String addressName) {
this.address= (this.address==null) ? new Address() : address;
this.address.setName(addressName);
}