[SPRING] Projection List에 의해 중첩 된 객체를 가져 오기위한 Hibernate Criteria를 작성하는 방법?
SPRINGProjection List에 의해 중첩 된 객체를 가져 오기위한 Hibernate Criteria를 작성하는 방법?
최대 절전 모드 프로젝션 목록에서 중첩 된 개체 값을 가져 오려고합니다. 나는 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 표준을 작성합니다.
나는 다음과 같은 기준으로 시도했다.
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에 null 값을 반환하는지 확인합니다. 이 SQL 쿼리에 대한 조건 작성 방법
해결법
-
==============================
1.나는 이런 종류의 요구 사항을 경험했다. 나는 중첩 된 객체를 Transformers.aliasToBean을 사용하여 중첩 된 객체로 만들려고했으나 작동하지 않습니다. 기본적으로 Transformers.aliasToBean에는 중첩 된 객체를 중첩 된 객체로 선택할 수있는 기능이 없습니다.
나는 이런 종류의 요구 사항을 경험했다. 나는 중첩 된 객체를 Transformers.aliasToBean을 사용하여 중첩 된 객체로 만들려고했으나 작동하지 않습니다. 기본적으로 Transformers.aliasToBean에는 중첩 된 객체를 중첩 된 객체로 선택할 수있는 기능이 없습니다.
내 질문 좀 봐.
프로젝션을 사용하여 자식 테이블에서 특정 열을 가져옵니다.
중첩 된 객체를 중첩 된 객체로 가져 오려면 해당 객체를 수행 할 수있는 Custom Transformer가 필요합니다.
samiandoni가 작성한 사용자 정의 변압기는 다음과 같습니다.
https://github.com/samiandoni/AliasToBeanNestedResultTransformer
해당 링크의 제공된 Readme에서
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
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의 변압기를 위의 변압기로 교체하면됩니다. 더 깊은 중첩 된 객체를 각각의 객체로 가져올 수 있습니다.
-
==============================
2.내 솔루션은 매우 기본입니다. 적절한 결과 변환기만큼 깨끗하지는 않지만 몇 가지 속성에 대한 빠른 투영을해야 할 때 유용합니다.
내 솔루션은 매우 기본입니다. 적절한 결과 변환기만큼 깨끗하지는 않지만 몇 가지 속성에 대한 빠른 투영을해야 할 때 유용합니다.
.add (Projections.property ( "tariff.amount"), "amount")) 대신 .add (Projections.property ( "tariff.amount"), "tariffAmount"))를 입력하십시오.
그런 다음 루트 객체 "setTariffAmount"에 setter를 추가하십시오.
public void setTariffAmount(String tariffAmount) { this.tariff = (this.tariff==null) ? new Tariff() : tariff; tariff.setAmount(tariffAmount); }
단점은 추가 메서드로 개체를 "더러워"한다는 것입니다.
-
==============================
3.AliasToBeanNestedResultTransformer는 다중 레벨 중첩 DTO를 처리하지 않습니다. 즉, 자신의 DTO에서 company.employee.location을 각각 수행 할 수 없습니다.
AliasToBeanNestedResultTransformer는 다중 레벨 중첩 DTO를 처리하지 않습니다. 즉, 자신의 DTO에서 company.employee.location을 각각 수행 할 수 없습니다.
다음은 다중 레벨 중첩 DTO를 처리하는 쓴 Transformer입니다. 다음과 같이 호출하여 사용할 수 있습니다.
희망이 도움이됩니다.
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)); } } }
}
from https://stackoverflow.com/questions/28970214/how-to-write-hibernate-criteria-to-take-nested-objects-by-projection-list by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] Eclipse : javadoc 추가 (0) | 2019.03.21 |
---|---|
[SPRING] 스프링 부트 2 및 OAuth2 / JWT 구성 (0) | 2019.03.21 |
[SPRING] MongoDB의 트랜잭션 (0) | 2019.03.21 |
[SPRING] 분리 된 객체는 최대 절전 모드에서 어떻게 작동합니까? (0) | 2019.03.21 |
[SPRING] 스프링 보안 Java 설정을 사용하여 HTTP 요청을 HTTPS로 리디렉션하는 방법은 무엇입니까? (0) | 2019.03.21 |