Anda dapat menambahkan SEPARATOR
sebagai kata kunci. Terapkan DialectResolver
Anda sendiri dan tambahkan kata kunci dalam huruf kecil ke dialek yang dihasilkan:
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;
}
}
Hal yang sama untuk versi Hibernate sebelum 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;
}
}
Anda kemudian harus memberi tahu Hibernate untuk menggunakan penyelesai dialek Anda. Misalnya di JPA Anda dapat melakukan ini di ketekunan Anda.xml:
<persistence>
<persistence-unit>
...
<property name="hibernate.dialect_resolvers" value="mypackage.MyDialectResolver"/>
</persistence-unit>
</persistence>
Hal yang sama berlaku untuk fungsi agregasi dalam dialek lain. Misalnya di Oracle WITHIN
kata kunci tidak ada.
Ada opsi lain, yang lebih independen terhadap basis data (dan yang saya sukai). Buat SQLFunction
berikut ini :
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 });
}
}
Anda dapat mendaftarkan fungsi ini di DialectResolver dengan cara yang sama seperti kata kunci di atas:
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());
}
Sekarang Anda dapat menggunakan fungsi ini dalam kueri JPQL / HQL / Kriteria Anda tanpa memikirkan sintaks dialek:
SELECT e.group, listagg(e.stringProperty, ', ') FROM Entity e GROUP BY e.group