Bạn có thể thêm SEPARATOR
làm từ khóa. Triển khai DialectResolver
của riêng bạn và thêm từ khóa in thường sang phương ngữ kết quả:
public class MyDialectResolver implements DialectResolver {
public Dialect resolveDialect(DialectResolutionInfo info) {
for (Database database : Database.values()) {
Dialect dialect = database.resolveDialect(info);
if (dialect != null) {
dialect.getKeywords().add("separator");
return dialect;
}
}
return null;
}
}
Tương tự đối với các phiên bản Hibernate trước 5.2.13 / 5.3.0:
public class MyDialectResolver extends StandardDialectResolver {
protected Dialect resolveDialectInternal(DatabaseMetaData metaData) throws SQLException {
Dialect dialect = super.resolveDialectInternal(metaData);
dialect.getKeywords().add("separator");
return dialect;
}
}
Sau đó, bạn sẽ phải yêu cầu Hibernate sử dụng trình phân giải phương ngữ của bạn. Ví dụ:trong JPA, bạn có thể làm điều này trong sự kiên trì của mình.xml:
<persistence>
<persistence-unit>
...
<property name="hibernate.dialect_resolvers" value="mypackage.MyDialectResolver"/>
</persistence-unit>
</persistence>
Điều tương tự cũng áp dụng cho các hàm tổng hợp trong các phương ngữ khác. Ví dụ trong Oracle, WITHIN
từ khóa bị thiếu.
Có một tùy chọn khác, độc lập với cơ sở dữ liệu hơn (và tôi thích hơn). Tạo SQLFunction
sau :
public class ListAggFunction implements SQLFunction {
/**
* The pattern that describes how the function is build in SQL.
*
* Replacements:
* {path} - is replaced with the path of the list attribute
* {separator} - is replaced with the separator (defaults to '')
* {orderByPath} - is replaced by the path that is used for ordering the elements of the list
*/
private String pattern;
/**
* Creates a new ListAggFunction definition which uses the ANSI SQL:2016 syntax.
*/
public ListAggFunction() {
this("LISTAGG(DISTINCT {path}, {separator}) WITHIN GROUP(ORDER BY {orderByPath})");
}
/**
* Creates a new ListAggFunction definition which uses a database specific syntax.
*
* @param pattern The pattern that describes how the function is build in SQL.
*/
public ListAggFunction(String pattern) {
this.pattern = pattern;
}
public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
return StringType.INSTANCE;
}
public boolean hasArguments() {
return true;
}
public boolean hasParenthesesIfNoArguments() {
return true;
}
public String render(Type firstArgumentType, List arguments,
SessionFactoryImplementor factory) throws QueryException {
if (arguments.isEmpty() || arguments.size() > 3) {
throw new IllegalArgumentException(
"Expected arguments for 'listagg': path [, separator [, order by path]]");
}
String path = (String) arguments.get(0);
String separator = arguments.size() < 2 ? "''" : (String) arguments.get(1);
String orderByPath = arguments.size() <= 2 ? path : (String) arguments.get(2);
return StringUtils.replaceEach(this.pattern, new String[] { "{path}", "{separator}", "{orderByPath}" },
new String[] { path, separator, orderByPath });
}
}
Bạn có thể đăng ký chức năng này trong DialectResolver theo cách tương tự như từ khóa ở trên:
if ("MySQL".equals(info.getDatabaseName()) || "H2".equals(info.getDatabaseName())) {
dialect.getFunctions().put("listagg", new ListAggFunction("GROUP_CONCAT(DISTINCT {path} ORDER BY {orderByPath} SEPARATOR {separator})"));
} else {
dialect.getFunctions().put("listagg", new ListAggFunction());
}
Giờ đây, bạn có thể sử dụng hàm này trong các truy vấn JPQL / HQL / Criteria của mình mà không cần suy nghĩ về cú pháp của phương ngữ:
SELECT e.group, listagg(e.stringProperty, ', ') FROM Entity e GROUP BY e.group