我想在Hibernate Projection List中使用嵌套对象值。我有OneToMany和ManyToOne关系的Pojo“ Charge”和“ Tariff”课程。
我的示例代码如下:
收费
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; }
关税
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; }
我想按收费模式从关税中提取金额值。
我写的SQL标准,即工作。
选择charge.amount,charge.name从charge,tariff那里的charge.name喜欢’s%’;
我尝试了以下标准。
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();
我只是用restclient检查它返回空值。如何编写此sql查询的条件?
我已经经历过这种要求。我尝试使用来将嵌套对象作为嵌套对象获取Transformers.aliasToBean,这将无法正常工作。默认情况下,Transformers.aliasToBean没有能力选择嵌套对象作为嵌套对象。
Transformers.aliasToBean
要将嵌套对象作为嵌套对象,您需要一个能够执行此操作的自定义变压器。
这是samiandoni撰写的Custom Transformer
https://github.com/samiandoni/AliasToBeanNestedResultTransformer
从该链接中提供的自述文件中
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
上面的转换器能够将一级嵌套对象作为嵌套对象来获取,并且不支持进一步的深层嵌套对象。因此,在进行一些挖掘之后,我找到了另一个自定义转换器,该转换器可以将深层嵌套对象作为嵌套对象进行提取
注意:
作者: Miguel Resendiz
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<?>>(); } }
只需将samiandoni的Transformer替换为上述变压器即可。它能够获取更深的嵌套对象作为各自的对象。