Java 在公式字段中使用Hibernate注册函数
我试图在公式字段中使用自定义hibernate方言中的注册函数。问题是公式字段没有使用我注册的函数。我在想我做错了什么 作为背景,我有一个应用程序,我正在为Oracle和Postgresql开发一个功能强大的应用程序。不是同时,而是针对部署到哪个数据库。我的模型中有几个公式字段,用于将OneToMany映射实体的名称聚合到一个逗号分隔的列表中,以便于搜索和显示。这是利用Listag完成的,当时它纯粹是Oracle。这在Postgresql中不起作用,但考虑到它需要在两种环境中都起作用,我不能将公式的语法更改为STRING_AGG。因此,我试图为这两个数据库注册一个函数,该函数将为正在使用的数据库使用适当的格式 我正在使用自定义方言扩展并注册我的函数,但它没有使用我注册的函数。我不确定我做错了什么 如果这实际上是不可能的,而我从错误的方向来处理这个问题,有没有一个好的方法来动态定义公式字段?不是在运行时,而是在编译时设置方言时Java 在公式字段中使用Hibernate注册函数,java,hibernate,jpa,Java,Hibernate,Jpa,我试图在公式字段中使用自定义hibernate方言中的注册函数。问题是公式字段没有使用我注册的函数。我在想我做错了什么 作为背景,我有一个应用程序,我正在为Oracle和Postgresql开发一个功能强大的应用程序。不是同时,而是针对部署到哪个数据库。我的模型中有几个公式字段,用于将OneToMany映射实体的名称聚合到一个逗号分隔的列表中,以便于搜索和显示。这是利用Listag完成的,当时它纯粹是Oracle。这在Postgresql中不起作用,但考虑到它需要在两种环境中都起作用,我不能将公
public class CustomPostgresqlDialect extends PostgreSQL95Dialect {
public CustomPostgresqlDialect() {
super();
registerFunction("MY_LISTAGG", new SQLFunctionTemplate( StandardBasicTypes.STRING, " STRING_AGG(?1 , ', ' ORDER BY ?1) "));
}
}
这是我的模型,公式如下:
public class Contractor extends Object implements Serializable {
...
@OneToMany(mappedBy = "contractor", fetch = FetchType.LAZY)
private Set<ProjectManager> projectManagers;
...
@Formula("(" +
"SELECT\r\n" +
" MY_LISTAGG(PM.NAME)\r\n" +
"FROM\r\n" +
" PROJECTMANAGERS PM\r\n" +
" INNER JOIN CONTRACTORS C ON C.ID = PM.FK_CONTRACTOR\r\n" +
"WHERE\r\n" +
" C.ID = id" +
")"
)
@NotAudited
private String pmNames;
...
}
public类Contractor扩展对象实现可序列化{
...
@OneToMany(mappedBy=“contractor”,fetch=FetchType.LAZY)
私人项目经理;
...
@公式(“(”+
“选择\r\n”+
“我的列表标签(PM.NAME)\r\n”+
“来自\r\n”+
“项目经理PM\r\n”+
“C.ID上的内部连接承包商C=PM.FK\U承包商\r\n”+
“其中\r\n”+
“C.ID=ID”+
")"
)
@未经审核
私有字符串名称;
...
}
您不能为此目的使用@Formula
。正如合同中所述:
您应该知道,@Formula
注释采用了可能影响数据库可移植性的本机SQL子句
您可以尝试使用JPQL/Criteria查询来实现此目的。就像SternK所写的那样,在
@Formula
中不可能使用JPQL/HQL函数,我还建议不要在一般的公式中使用子查询,因为即使您不需要数据,也会导致始终执行这些子查询的惩罚
我认为这是一个完美的用例
我创建了这个库,以便在JPA模型和自定义接口或抽象类定义的模型之间进行简单的映射,类似于类固醇上的Spring数据投影。其思想是以您喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(getter)映射到实体模型
在Blaze持久性实体视图中,您的用例的DTO模型可能如下所示:
@EntityView(Contractor.class)
public interface ContractorDto {
@IdMapping
Long getId();
@Mapping(value = "projectManagers.name", fetch = MULTISET)
Set<String> getPmNames();
}
最好的是,它只会获取实际需要的状态!因此,在本例中,将创建如下所示的SQL查询:
select
c.id,
(
select json_agg(json_object(c1, pm.name))
from project_manager pm
where pm.fk_contractor = c.id
)
from contractor c
如果确实需要聚合字符串,还可以使用映射中的GROUP\u CONCAT
函数:
@EntityView(Contractor.class)
public interface ContractorDto {
@IdMapping
Long getId();
@Mapping("GROUP_CONCAT(projectManagers.name, 'SEPARATOR', ', ', 'ORDER BY', projectManagers.name,, 'ASC')")
String getPmNames();
}
哦我认为它可以工作,因为在我将其注册为Oracle的关键字之前,inthein在公式中造成了问题。我希望它能用我应用于函数的本机SQL片段替换为该函数注册的名称。这看起来真是难以置信。仅拥有基于代码的“视图”的能力将非常有用!然而,我确实有一个关于小组讨论的问题。在您链接的文档部分中,它指出并非所有DBMS都支持这一点。快速搜索表明Oracle和Postgres都不支持内部的GROUP_CONCAT功能。我仍然需要阅读Blazebit文档,但是映射注释是否与公式字段(即,一个直接的SQL片段)做相同的事情?在这种情况下,您的示例对我来说不起作用,因为GROUP_CONCAT不存在。
GROUP_CONCAT
正是我们为此选择的名称,但许多DBMS都有实现,包括Oracle和PostgreSQL分别通过listag
和string_agg
实现。@Mapping
中的表达式位于“JPQL.next”中,表达式文档将对此进行进一步解释。
select
c.id,
(
select json_agg(json_object(c1, pm.name))
from project_manager pm
where pm.fk_contractor = c.id
)
from contractor c
@EntityView(Contractor.class)
public interface ContractorDto {
@IdMapping
Long getId();
@Mapping("GROUP_CONCAT(projectManagers.name, 'SEPARATOR', ', ', 'ORDER BY', projectManagers.name,, 'ASC')")
String getPmNames();
}