|
Люди, использующие Criteria API, явно или неявно пользуются ResultTransformer. ResultTransformer – это хороший и простой интерфейс, позволяющий вам преобразовать любой результат выполнения запроса Criteria. Т.е. вы можете сделать так, чтобы результат выполнения Criteria возвращался в виде java.util.Map или non-entity Bean.
Criteria Transformers Представьте, что у вас есть класс StudentDTO: public class StudentDTO { private String studentName; private String courseDescription; public StudentDTO() { } ... }
еперь вы можете сделать так, чтобы ваш Criteria возвращал классы, не ассоциированные с сущностями вместо массивов или сущностей. Это можно сделать с помощью ResultTransformer: List resultWithAliasedBean = s.createCriteria(Enrolment.class) .createAlias("student", "st").createAlias("course", "co") .setProjection( Projections.projectionList() .add( Projections.property("st.name"), "studentName" ) .add( Projections.property("co.description"), "courseDescription" ) ) .setResultTransformer( Transformers.aliasToBean(StudentDTO.class) ) .list(); StudentDTO dto = (StudentDTO)resultWithAliasedBean.get(0); Все это благодаря тому, что ResultTransformer стал доступен после внедрения нами Criteria API в Hibernate 3. Это всего лишь один пример встроенного класса—трансформера. Пользователи могут создавать свои классы, такие как им нужно. Зависть в программировании Так как я больше предпочитаю HQL/SQL, я завидовал Criteria в том, что оно имеет такую функцию. И получал много запросов от пользователей на добавление ее во все средства запросов Hibernate. Сегодня я положил конец этой зависти и добавил поддержку ResultTranformer для HQL и SQL в hibernate 3.2. HQL Transformers В HQL у нас уже было что-то вроде трансформера (использование «select new» в [http://www.hibernate.org/hib_docs/v3/reference/en/html/queryhql.html#queryhql-select]). Ограничение этого метода состоит в том, что он может задавать значения bean классов только с помощи конструктора. Следовательно, если мы используем один и тот же класс в нескольких сценариях, мы должны иметь в нем (классе) множество конструкторов, исключительно для того, чтобы работали конструкции «select new». Теперь вы можете получить объект класса, заполненный с использованием методов свойств или непосредственно полей, исключая использование конструкторов. List resultWithAliasedBean = s.createQuery( "select e.student.name as studentName," + " e.course.description as courseDescription" + "from Enrolment as e") .setResultTransformer( Transformers.aliasToBean(StudentDTO.class)) .list(); StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0); SQL Transformers При использовании native SQL возвращаемые non-entity beans или Map зачастую более удобны, чем просто Object[]. С result transformers это теперь возможно. List resultWithAliasedBean = s.createSQLQuery( "SELECT st.name as studentName, co.description as courseDescription " + "FROM Enrolment e " + "INNER JOIN Student st on e.studentId=st.studentId " + "INNER JOIN Course co on e.courseCode=co.courseCode") .addScalar("studentName") .addScalar("courseDescription") .setResultTransformer( Transformers.aliasToBean(StudentDTO.class)) .list(); StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0); Совет: вызовы addScalar() необходимы в HSQLDB для распознавания имени свойства, потому что она возвращает имена столбцов в верхнем регистре (например, «STUDENTNAME»). Эта проблема также может быть решена с помощью специального класса—трансформера, который будет искать имена свойств, вместо использования явного соответствия – может быть вы реализуете метод fuzzyAliasToBean() :) Map vs. Object[] Так как вы можете использовать трансформер, который возвращает Map из alias to value/entity (например, Transformers.ALIAS_TO_MAP), вам больше не надо связываться с индексированными массивами для работы с результатами запроса. List iter = s.createQuery( "select e.student.name as studentName," + " e.course.description as courseDescription" + "from Enrolment as e") .setResultTransformer( Transformers.ALIAS_TO_MAP ) .iterate(); String name = (Map)(iter.next()).get("studentName"); Еще раз напомню, это работает как для Criteria, так и для HQL и Native SQL. Достижение нирваны с native sql Нам все еще не хватает некоторых вещей, но с добавлением поддержки ResultTranformer для SQL и некоторых других дополнительных функций за последнее время в работу с native SQL, мы приблизились к достижению нирваны в поддержке native SQL. В комбинации с StatelessSession вы получаете очень гибкое и мощное решение «sql executor», которе может прозрачно выполнять отображение объектов в и из native SQL без каких либо накладных расходов ORM. … и когда вы приметесь управлять SQL, статусом, жизненным циклом и кешированием ваших объектов вручную и захотите получить все преимущества ORM, тогда вы увидите, что это давно ждет вас в готовом виде:) |