Hibernate @Formula 不包含架构
Posted
技术标签:
【中文标题】Hibernate @Formula 不包含架构【英文标题】:Hibernate @Formula doesn't include Schema 【发布时间】:2018-12-07 20:09:41 【问题描述】:我有一个具有 @Formula 属性的实体,如下所示:
@Entity
@Table(name = "areasAuxiliar")
public final class AreaAuxiliar implements Serializable
@Id
@Column(name = "idArea")
private Integer idArea;
@Formula("RUTAAREA(idArea)")
private String ruta;
当我将休眠配置为指向 Oracle 数据库时,我没有问题, 但是,当我切换到 SQLServer 时,休眠不包括 shema 并且查询失败,
为休眠生成的查询如下所示:
select
areaauxili4_.idArea as idArea1_6_4_,
rutaArea(areaauxili4_.idArea) as formula2_4_
from
SIGAP.areasAuxiliar areaauxili4_
参数 hibernate.default_schema=SIGAP 正在被读取并包含在表中,但未包含在函数中,
是否有一个选项/注释可以在该函数中强制使用 shema?
我尝试过休眠 5.1 和 5.2,结果相同 :(
【问题讨论】:
你在这里指的是什么功能? AFAIK,@Formula.value
的内容逐字传递给查询。为RUTAAREA
创建一个全局别名(但不确定SQLServer 是否支持这种别名)或在RUTAAREA
前面加上架构名称
@crizzis 我无法在代码中添加架构,因为它可以更改我无法为每种情况构建自定义部署,我不确定,但可以为表而不是函数创建别名: (
@crizzis 我为该函数添加了一个别名到 dbo 但它是相同的,查询结束如下: select dbo.RUTAAREA(idarea) from sigap.areasAuxiliar;没有“dbo”就无法识别。
我想这就是你要找的东西:***.com/questions/43635745/…
【参考方案1】:
更简化的解决方案:
从此更改您的@Formula:
@Formula("RUTAAREA(idArea)")
到这里:
@Formula("MYAPP_SCHEMA.RUTAAREA(idArea)")
创建一个类:
public class HibernateEntityInterceptor extends EmptyInterceptor
在你的 sessionFactory 中将它注册为实体拦截器,在我的例子中:
sessionFactory.setEntityInterceptor(new HibernateEntityInterceptor());
然后在那个类中你重写这个方法:
public String onPrepareStatement(String sql)
该方法在执行之前接收 sql 命令,因此,您只需简单地全部替换即可:
sql = sql.replaceAll("\\MYAPP_SCHEMA", default_schema);
return sql;
感谢您的帮助。
【讨论】:
@Dan 不要误会我的意思,这几乎是你的答案,但我试图让它更清楚,并且只替换模式的关键字,而不是模式+函数,所以这可以也可以使用 NamedNativeQuery【参考方案2】:不确定这是否有助于应用于函数,但您是否尝试将属性“模式”添加到 @Table
注释:
@Entity
@Table(name = "areasAuxiliar", schema="mySchemaName")
public final class AreaAuxiliar implements Serializable
@Id
@Column(name = "idArea")
private Integer idArea;
@Formula("RUTAAREA(idArea)")
private String ruta;
另一种解决方案,转换为注释,是在@Formula
注解中使用占位符
@Entity
@Table(name = "areasAuxiliar")
public final class AreaAuxiliar implements Serializable
@Id
@Column(name = "idArea")
private Integer idArea;
@Formula("SCHEMA_AND_FUNCTION")
private String ruta;
然后添加一个拦截器来填充公式的值。解决方案的链接是Hibernate @Formula set value at runtime
最后,请参阅我关于在 SQLSERVER 中创建全局函数的评论。详情可以在这里找到Can I create create a global function in SQL Server?
【讨论】:
【参考方案3】:1) 我知道对于 native 查询,您可以使用“h-schema”占位符(将填充“hibernate.default_schema”参数的值):
"SELECT x FROM h-schematableName"
试一试,看看这是否也适用于@Formula...
2)如果没有,您也可以尝试使用替换(即 hibernate.query.substitutions)来告诉休眠将文字 S 替换为 S' - 在您的情况下 "RUTAAREA" 与 "schema.RUTAAREA" ?
【讨论】:
您是否尝试过第二种解决方法(有替换)?【参考方案4】:您可以使用mysql-orm.xml
文件覆盖您的公式,然后将您的构建配置为在数据库为 mysql 时考虑该文件。
在这里覆盖公式:
<entity-mappings
xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm orm_2_1.xsd"
version="2.1">
<package>com.acme.persistence</package>
<entity class="AreaAuxiliar" access="FIELD">
<attributes>
<property name="ruta" formula="schemaName.RUTAAREA(idarea)"/>
</attributes>
</entity>
</entity-mappings>
然后在特定的persistence.xml
中添加引用。然后,您可以在构建或运行时使用此文件覆盖默认的 persistence.xml(参见下面的链接)。
<persistence
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="persistenceUnit">
<provider>
org.hibernate.jpa.HibernatePersistenceProvider
</provider>
<mapping-file>
mappings/identifier/global/mysql-orm.xml
</mapping-file>
<class>
com.acme.persistence.AreaAuxiliar
</class>
</persistence-unit>
注意:大量灵感来自 How to change Hibernate GenerationType identifier depending on the underlying database
注(2):在blog post和here中,作者在运行时生成PersistenceUnitInfo。
【讨论】:
以上是关于Hibernate @Formula 不包含架构的主要内容,如果未能解决你的问题,请参考以下文章
将 Hibernate @Formula (case) 转换为 JOOQ 字段