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 字段

使用 Hibernate 加入 @Formula

Citardauq Formula无法正常工作

当前不支持公式映射 - Hibernate ORM Envers

hibernate 常识

生成的查询包含架构和目录名称