如何编写Hibernate Criteria以通过Projection List获取嵌套对象? [英] how to write Hibernate Criteria to take nested objects by Projection List?

查看:310
本文介绍了如何编写Hibernate Criteria以通过Projection List获取嵌套对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Hibernate Projection List中使用Nested对象值。我与OneToMany和ManyToOne关系有Pojo'Charge'和'Tariff'类。



我的示例代码如下:

收费

 私人字符串ID; 
私人关税关税;
私人字符串名称;

@OneToMany(cascade = {CascadeType.ALL},fetch = FetchType.EAGER,mappedBy =charge)
public Tariff getTariff(){
return tariff;
}
public void setTariff(关税关税){
this.tariff =关税;
}

关税

 私人字符串ID; 
私人字符串金额;
私人收费;

@ManyToOne(cascade = {CascadeType.PERSIST},fetch = FetchType.EAGER)
@JoinColumn(name =charge_id)
public Charge getCharge(){
退货费用;
}
public void setCharge(Charge charge){
this.charge = charge;
}

我想从收费模式中获取金额值。



我编写的sql标准可以工作,即。

lockquote

SELECT tariff.amount, charge.name FROM charge,tariff WHERE
charge.name LIKE'%';


我尝试了以下条件。

  Criteria cr = getSession()。createCriteria(Charge.class,charge)
.createAlias( (Projection.projectionList(),
.add(Projected.property(chargeName),chargeName)
.add(Projection。属性(id),id)
.add(Projections.property(tariff.amount),amount))
.add(Restrictions.like(chargeName,name + %))
.setResultTransformer(Transformers.aliasToBean(Charge.class));
return cr.list();

我只是用restclient检查它是否返回空值。如何为这个sql查询编写Criteria?

解决方案

我经历过这种需求。我尝试使用 Transformers.aliasToBean 获取嵌套对象作为嵌套对象,这将无法工作。默认情况下, Transformers.aliasToBean 不能选择嵌套对象作为嵌套对象。



你可以看看我的问题



要获取嵌套对象作为嵌套对象,您需要一个自定义变压器,这是能够做到这一点。



这是由samiandoni编写的自定义变压器



https://github.com/samiandoni/AliasToBeanNestedResultTransformer



从在该链接中提供自述

  class Person {
private Long id;
私人字符串名称;
私家车车;
// getters and setters
}

class Car {
private Long id;
私有字符串颜色;
//获得者和设置者
}

列表< Person> getPeople(){
ProjectionList预测= Projections.projectionList()
.add(Projections.id()。as(id))
.add(Projections.property(name ).as(name))
.add(Projections.property(c.id)。as(car.id))
.add(Projections.property(c。色 ),为( car.color));

Criteria criteria = getCurrentSession()。createCriteria(Person.class)
.createAlias(car,c)
.setProjection(预测)
。 setResultTransformer(新的AliasToBeanNestedResultTransformer(Person.class));

return(List< Person>)criteria.list();
}

//每个人的车将被填充

上面的转换器能够抓取一级嵌套对象作为嵌套对象,并且不支持更深的嵌套对象。所以经过一番挖掘后,我发现了另一个Custom转换器,它可以抓取深嵌套对象作为嵌套对象。



注意:

作者 Miguel Resendiz

  import java.lang.reflect.Field; 
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.hibernate.transform.ResultTransformer;

/ **
*使用嵌套alises变换alises的帮助
*
* @author Miguel Resendiz
*
* /
public class AliasToBeanNestedResultTransformer extends
AliasedTupleSubsetResultTransformer {

private static final long serialVersionUID = -8047276133980128266L;

private static final int TUPE_INDEX = 0;
private static final int ALISES_INDEX = 1;
private static final int FIELDNAME_INDEX = 2;

private static final PropertyAccessor accessor = PropertyAccessorFactory
.getPropertyAccessor(property);

private final Class<?> resultClass;

private Object [] entityTuples;
private String [] entityAliases;

私人地图< String,Class<>> fieldToClass = new HashMap< String,Class<>>();
私人地图< String,List<>> subEntities = new HashMap< String,List<>>();
私人列表< String> nestedAliases = new ArrayList< String>();
私人地图< String,Class<>> listFields = new HashMap< String,Class<>>();
$ b $ public boolean isTransformedValueATupleElement(String [] aliases,
int tupleLength){
return false;
}

public AliasToBeanNestedResultTransformer(Class<?> resultClass){

this.resultClass = resultClass;


public Object transformTuple(Object [] tuple,String []别名){

handleSubEntities(tuple,aliases);
cleanParams(元组,别名);
ResultTransformer rootTransformer = new AliasToBeanResultTransformer(
resultClass);
Object root = rootTransformer.transformTuple(entityTuples,
entityAliases);

loadSubEntities(root);

cleanMaps();
返回root;
}

private void handleSubEntities(Object [] tuple,String []别名)
抛出HibernateException {
String fieldName =;
String aliasName =;
尝试{
for(int i = 0; i< aliases.length; i ++){
String alias = aliases [i];
if(alias.contains(。)){

String [] sp = alias.split(\\\。);
StringBuilder aliasBuilder = new StringBuilder();
for(int j = 0; j if(j == 0){
fieldName = sp [j];
} else {
aliasBuilder.append(sp [j]);
aliasBuilder.append(。);
}
}
aliasName = aliasBuilder.substring(0,
aliasBuilder.length() - 1);

nestedAliases.add(别名);
manageEntities(fieldName,aliasName,tuple [i]);
}
}
} catch(NoSuchFieldException e){
throw new HibernateException(无法实例化resultclass:
+ resultClass.getName()+for field名称:+ fieldName
+和别名:+ aliasName);
}
}

private Class<?> findClass(String fieldName)抛出NoSuchFieldException,
SecurityException {$ b $ if(fieldToClass.containsKey(fieldName)){
return fieldToClass.get(fieldName);
} else {
Class<?> subclass = resultClass.getDeclaredField(fieldName)
.getType();

if(subclass.equals(List.class)|| subclass.equals(Set.class)){
if(subclass.equals(List.class)){
listFields.put(fieldName,LinkedList.class);
} else {
listFields.put(fieldName,HashSet.class);
}
Field field = resultClass.getDeclaredField(fieldName);
ParameterizedType genericType =(ParameterizedType)字段
.getGenericType();
subclass =(Class<>)genericType.getActualTypeArguments()[0];

}
fieldToClass.put(fieldName,subclass);
返回子类;


$ b @SuppressWarnings(unchecked)
private void manageEntities(String fieldName,String aliasName,
Object tupleValue)throws NoSuchFieldException,SecurityException {
Class<?> subclass = findClass(fieldName);
if(!subEntities.containsKey(fieldName)){
List< Object> list = new ArrayList< Object>();
list.add(new ArrayList< Object>());
list.add(new ArrayList< String>());
list.add(FIELDNAME_INDEX,子类);
subEntities.put(fieldName,list); $(b

((List< Object>)subEntities.get(fieldName).get(TUPE_INDEX))
.add(tupleValue);
((List< String>)subEntities.get(fieldName).get(ALISES_INDEX))
.add(aliasName);

$ b $ private void cleanParams(Object [] tuple,String [] aliases){
entityTuples = new Object [aliases.length - nestedAliases.size()];
entityAliases = new String [aliases.length - nestedAliases.size()];

for(int j = 0,i = 0; j if(!nestedAliases.contains(aliases [j])){
entityTuples [i] = tuple [j];
entityAliases [i] =别名[j];
++ i;



$ @SuppressWarnings({unchecked,rawtypes})
private void loadSubEntities(Object root)throws HibernateException {
尝试{
for(String fieldName:subEntities.keySet()){
Class<?> subclass =(Class<> subEntities.get(fieldName).get(
FIELDNAME_INDEX);

ResultTransformer subclassTransformer = new AliasToBeanNestedResultTransformer(
subclass);

Object subObject = subclassTransformer.transformTuple(
((List< Object>)subEntities.get(fieldName).get(0))
.toArray(),
((List< Object>)subEntities.get(fieldName).get(1))
.toArray(new String [0]));

Setter setter = accessor.getSetter(resultClass,fieldName);
if(listFields.containsKey(fieldName)){
Class<?> collectionClass = listFields.get(fieldName);
Collection subObjectList =(Collection)collectionClass
.newInstance();
subObjectList.add(subObject);
setter.set(root,subObjectList,null);
} else {
setter.set(root,subObject,null);

$ b $ catch(Exception e){
throw new HibernateException(e);



private void cleanMaps(){
fieldToClass = new HashMap< String,Class<>>();
subEntities = new HashMap< String,List<>>();
nestedAliases = new ArrayList< String>();
listFields = new HashMap< String,Class<>>();
}

}

只需将samiandoni的变压器替换为上述变压器。它能够将更深的嵌套对象作为各自的对象获取。


I want to take Nested object values in Hibernate Projection List. I having Pojo 'Charge' and 'Tariff' class with OneToMany and ManyToOne relations.

My sample code is as following:

Charge

private String id;              
private Tariff tariff;
private String name;

@OneToMany(cascade=   {CascadeType.ALL},fetch=FetchType.EAGER,mappedBy="charge")
public Tariff getTariff() {
    return tariff;
}
public void setTariff(Tariff tariff) {
    this.tariff = tariff;
}

Tariff

private String id;
private String amount;
private Charge charge;

@ManyToOne(cascade={CascadeType.PERSIST},fetch=FetchType.EAGER)
@JoinColumn(name="charge_id")
public Charge getCharge() {
    return charge;
}
public void setCharge(Charge charge) {
    this.charge = charge;
}

I want to take amount value from tariff by charge model.

I write sql criteria that works ie.

SELECT tariff.amount,charge.name FROM charge,tariff WHERE charge.name LIKE 's%';

and i tried with following criteria.

Criteria cr = getSession().createCriteria(Charge.class,"charge")
    .createAlias("charge.tariff","tariff")
    .setProjection(Projections.projectionList()
    .add(Projections.property("chargeName"),"chargeName")
    .add(Projections.property("id"),"id")
    .add(Projections.property("tariff.amount"),"amount"))
    .add(Restrictions.like("chargeName", name+"%"))
    .setResultTransformer(Transformers.aliasToBean(Charge.class));
     return  cr.list(); 

I just check with restclient it returns null Value. How to write for Criteria for this sql Query ?

解决方案

I've experienced this kind of requirement. I tried to get nested objects as nested objects using Transformers.aliasToBean, which will not work. By default, Transformers.aliasToBean don't have the capability to select nested object as nested object.

You can take a look at my question

Using Projecions to fetch a particular column from child table

To get Nested object as nested object, you need a Custom Transformer which is capable of doing that.

Here's a Custom Transformer written by samiandoni

https://github.com/samiandoni/AliasToBeanNestedResultTransformer

From the provided Readme in that link

class Person {
  private Long id;
  private String name;
  private Car car;
  // getters and setters
}

class Car {
  private Long id;
  private String color;
  // getters and setters
}

List<Person> getPeople() {
  ProjectionList projections = Projections.projectionList()
    .add(Projections.id().as("id"))
    .add(Projections.property("name").as("name"))
    .add(Projections.property("c.id").as("car.id"))
    .add(Projections.property("c.color").as("car.color"));

  Criteria criteria = getCurrentSession().createCriteria(Person.class)
    .createAlias("car", "c")
    .setProjection(projections)
    .setResultTransformer(new AliasToBeanNestedResultTransformer(Person.class));

  return (List<Person>) criteria.list();
}

// each car of Person will be populated

The above transformer is capable of Fetching first level Nested object as Nested object and it doesn't support further deep nested objects. So after some digging I've found another Custom transformer which is capable of Fetching deep Nested objects as Nested objects

Note:

Author: Miguel Resendiz

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.hibernate.transform.ResultTransformer;

/**
 * Help to transform alises with nested alises
 * 
 * @author Miguel Resendiz
 * 
 */
public class AliasToBeanNestedResultTransformer extends
AliasedTupleSubsetResultTransformer {

    private static final long serialVersionUID = -8047276133980128266L;

    private static final int TUPE_INDEX = 0;
    private static final int ALISES_INDEX = 1;
    private static final int FIELDNAME_INDEX = 2;

    private static final PropertyAccessor accessor = PropertyAccessorFactory
            .getPropertyAccessor("property");

    private final Class<?> resultClass;

    private Object[] entityTuples;
    private String[] entityAliases;

    private Map<String, Class<?>> fieldToClass = new HashMap<String, Class<?>>();
    private Map<String, List<?>> subEntities = new HashMap<String, List<?>>();
    private List<String> nestedAliases = new ArrayList<String>();
    private Map<String, Class<?>> listFields = new HashMap<String, Class<?>>();

    public boolean isTransformedValueATupleElement(String[] aliases,
            int tupleLength) {
        return false;
    }

    public AliasToBeanNestedResultTransformer(Class<?> resultClass) {

        this.resultClass = resultClass;
    }

    public Object transformTuple(Object[] tuple, String[] aliases) {

        handleSubEntities(tuple, aliases);
        cleanParams(tuple, aliases);
        ResultTransformer rootTransformer = new AliasToBeanResultTransformer(
                resultClass);
        Object root = rootTransformer.transformTuple(entityTuples,
                entityAliases);

        loadSubEntities(root);

        cleanMaps();
        return root;
    }

    private void handleSubEntities(Object[] tuple, String[] aliases)
            throws HibernateException {
        String fieldName = "";
        String aliasName = "";
        try {
            for (int i = 0; i < aliases.length; i++) {
                String alias = aliases[i];
                if (alias.contains(".")) {

                    String[] sp = alias.split("\\.");
                    StringBuilder aliasBuilder = new StringBuilder();
                    for (int j = 0; j < sp.length; j++) {
                        if (j == 0) {
                            fieldName = sp[j];
                        } else {
                            aliasBuilder.append(sp[j]);
                            aliasBuilder.append(".");
                        }
                    }
                    aliasName = aliasBuilder.substring(0,
                            aliasBuilder.length() - 1);

                    nestedAliases.add(alias);
                    manageEntities(fieldName, aliasName, tuple[i]);
                }
            }
        } catch (NoSuchFieldException e) {
            throw new HibernateException("Could not instantiate resultclass: "
                    + resultClass.getName() + " for field name: " + fieldName
                    + " and alias name:" + aliasName);
        }
    }

    private Class<?> findClass(String fieldName) throws NoSuchFieldException,
    SecurityException {
        if (fieldToClass.containsKey(fieldName)) {
            return fieldToClass.get(fieldName);
        } else {
            Class<?> subclass = resultClass.getDeclaredField(fieldName)
                    .getType();

            if (subclass.equals(List.class) || subclass.equals(Set.class)) {
                if (subclass.equals(List.class)) {
                    listFields.put(fieldName, LinkedList.class);
                } else {
                    listFields.put(fieldName, HashSet.class);
                }
                Field field = resultClass.getDeclaredField(fieldName);
                ParameterizedType genericType = (ParameterizedType) field
                        .getGenericType();
                subclass = (Class<?>) genericType.getActualTypeArguments()[0];

            }
            fieldToClass.put(fieldName, subclass);
            return subclass;
        }
    }

    @SuppressWarnings("unchecked")
    private void manageEntities(String fieldName, String aliasName,
            Object tupleValue) throws NoSuchFieldException, SecurityException {
        Class<?> subclass = findClass(fieldName);
        if (!subEntities.containsKey(fieldName)) {
            List<Object> list = new ArrayList<Object>();
            list.add(new ArrayList<Object>());
            list.add(new ArrayList<String>());
            list.add(FIELDNAME_INDEX, subclass);
            subEntities.put(fieldName, list);
        }
        ((List<Object>) subEntities.get(fieldName).get(TUPE_INDEX))
        .add(tupleValue);
        ((List<String>) subEntities.get(fieldName).get(ALISES_INDEX))
        .add(aliasName);
    }

    private void cleanParams(Object[] tuple, String[] aliases) {
        entityTuples = new Object[aliases.length - nestedAliases.size()];
        entityAliases = new String[aliases.length - nestedAliases.size()];

        for (int j = 0, i = 0; j < aliases.length; j++) {
            if (!nestedAliases.contains(aliases[j])) {
                entityTuples[i] = tuple[j];
                entityAliases[i] = aliases[j];
                ++i;
            }
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void loadSubEntities(Object root) throws HibernateException {
        try {
            for (String fieldName : subEntities.keySet()) {
                Class<?> subclass = (Class<?>) subEntities.get(fieldName).get(
                        FIELDNAME_INDEX);

                ResultTransformer subclassTransformer = new AliasToBeanNestedResultTransformer(
                        subclass);

                Object subObject = subclassTransformer.transformTuple(
                        ((List<Object>) subEntities.get(fieldName).get(0))
                        .toArray(),
                        ((List<Object>) subEntities.get(fieldName).get(1))
                        .toArray(new String[0]));

                Setter setter = accessor.getSetter(resultClass, fieldName);
                if (listFields.containsKey(fieldName)) {
                    Class<?> collectionClass = listFields.get(fieldName);
                    Collection subObjectList = (Collection) collectionClass
                            .newInstance();
                    subObjectList.add(subObject);
                    setter.set(root, subObjectList, null);
                } else {
                    setter.set(root, subObject, null);
                }
            }
        } catch (Exception e) {
            throw new HibernateException(e);
        }
    }

    private void cleanMaps() {
        fieldToClass = new HashMap<String, Class<?>>();
        subEntities = new HashMap<String, List<?>>();
        nestedAliases = new ArrayList<String>();
        listFields = new HashMap<String, Class<?>>();
    }

}

Just replace samiandoni's Transformer with the above transformer. It's capable of fetching further deep Nested Objects as respective Objects.

这篇关于如何编写Hibernate Criteria以通过Projection List获取嵌套对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆