Нельзя использовать фрагменты SQL в запросах JPQL или критериях ...
... кроме случаев, когда ...
1.Вызов функции
JPA и Hibernate позволяют использовать функции в их выражениях, например:
... ORDER BY trim(entity.label) ASC
Resp.
query.orderBy(criteriaBuilder.asc(
criteriaBuilder.function("trim", String.class, root.get(ExampleEntity_.label))));
Проблема в том, что этона самом деле не вызов функции SQL trim
, а вызов функции JPA, которая должна быть зарегистрирована (Hibernate делает это уже для наиболее распространенных функций SQL).
К счастью, вы можете определить свои собственные функции JPA в DialectResolver
:
public class MyDialectResolver implements DialectResolver {
public Dialect resolveDialect(final DialectResolutionInfo info) {
Dialect dialect = StandardDialectResolver.INSTANCE.resolve(info);
dialect.registerFunction("myOrderFunction", ...);
return dialect;
}
}
registerFunction
принимает два параметра, первый - это имя функции в JPA, другой -сопоставление с SQL.
Не забудьте объявить свой преобразователь диалекта в вашем persistence.xml
:
<persistence-unit name="database">
<properties>
<property name="hibernate.dialect_resolvers"
value="my.package.MyDialectResolver" />
</properties>
</persistence-unit>
Теперь вы можете создать свою собственную функцию на своем сервере SQL, которая содержит ваш огромный SQL и зарегистрируйте это как функцию:
dialect.registerFunction("myOrderFunction",
new StandardSQLFunction("myOrderFunctionInSQL", StringType.INSTANCE));
Или вы можете написать свое собственное отображение, которое включает в себя ваш огромный SQL :
public class MyOrderFunction implements SQLFunction {
public String render((Type firstArgumentType, List arguments,
SessionFactoryImplementor factory) throws QueryException) {
return my_huge_SQL;
}
// ...
}
И зарегистрируйте это:
dialect.registerFunction("myOrderFunction", new MyOrderFunction());
Еще одно преимущество этого решения: вы можете определять различные SQL в зависимости от фактического диалекта базы данных.
2.Используя формулу
Вы можете использовать дополнительный атрибут для вашей сущности:
@Formula("my huge SQL")
private String orderAttribute;
Теперь вы можете сортировать по этому атрибуту:
... ORDER BY entity.orderAttribute ASC
Респ.
query.orderBy(criteriaBuilder.asc(root.get(ExampleEntity_.orderAttribute))));
Я рекомендую это решение, только если вам все равно нужен результат огромного SQL в вашей модели.В противном случае это только загрязнит вашу модель сущности и добавит SQL в каждый запрос вашей сущности (за исключением того, что вы пометите его @Basic(fetch = FetchType.lazy)
и будете использовать инструментарий байт-кода ).
Аналогичным решением было бы определение сущности @Subselect
с огромным SQL - с теми же недостатками.