【问题标题】:Hibernate formula not finding column names休眠公式找不到列名
【发布时间】:2018-07-27 23:17:44
【问题描述】:

对公式有点兴趣,这让我发疯。 我们有一些代码可以通过公式获取实体,数据库中没有链接,需要在运行时完成,因此使用了@Formula。这是该类的外观:

@Entity
@Table(name="T_EMPLOYEE_COMPANY_ASSIGNMENT"
)

public class EmployeeCompanyAssignment  implements java.io.Serializable {



public EmployeeCompanyAssignment() {
}

@EmbeddedId
@AttributeOverrides( {
    @AttributeOverride(name="employeeId", column=@Column(name="EMPLOYEE_ID", nullable=false, precision=10, scale=0) ), 
    @AttributeOverride(name="companyId", column=@Column(name="COMPANY_ID", nullable=false, precision=10, scale=0) ) } )
public EmployeeCompanyAssignmentId getId() {
    return this.id;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="EMPLOYEE_ID", nullable=false, insertable=false, updatable=false)
public Employee getEmployee() {
    return this.employee;
}

public void setEmployee(Employee employee) {
    this.employee = employee;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="COMPANY_ID", nullable=false, insertable=false, updatable=false)
public Company getCompany() {
    return this.company;
}

public void setCompany(Company company){
    this.company = company;
}
@Column(name="DEFAULT_WBS_SAP_CODE", length=24)
public String getDefaultWbsSapCode() {
    return this.defaultWbsSapCode;
}

public void setDefaultWbsSapCode(String defaultWbsSapCode){
    this.defaultWbsSapCode = defaultWbsSapCode;
}
@Column(name="DEFAULT_COST_CENTER_SAP_CODE", length=10)
public String getDefaultCostCenterSapCode() {
    return this.defaultCostCenterSapCode;
}

public void setDefaultCostCenterSapCode(String defaultCostCenterSapCode){
    this.defaultCostCenterSapCode = defaultCostCenterSapCode;
}
....
}

公式是这样设置的:

@Formula(value = "(SELECT * FROM(" +
        "Select *" +
            " from T_COST_CENTER cc" +
            " where cc.is_blocked_in_sap = 0" +
                " and cc.is_deleted_in_sap = 0" +
                " and cc.company_id in" +
                    " (SELECT TECA.COMPANY_ID" +
                        " FROM T_EMPLOYEE_COMPANY_ASSIGNMENT TECA" +
                        " WHERE TECA.EMPLOYEE_ID = EMPLOYEE_ID)" +
        " and LTRIM(" +
                "(SELECT *" +
                 " FROM (select TECA.DEFAULT_COST_CENTER_SAP_CODE" +
                         " from T_EMPLOYEE_COMPANY_ASSIGNMENT TECA" +
                        " WHERE TECA.EMPLOYEE_ID = EMPLOYEE_ID)" +
                " where ROWNUM = 1)" +
            ", '0') = LTRIM(cc.sap_code, '0')" +
        " order by cc.sap_code DESC" +
        ")" +
        " WHERE ROWNUM = 1" +
        ")")
public CostCenter getDefaultCostCenter() {
    return defaultCostCenter;
}
public void setDefaultCostCenter(CostCenter defaultCostCenter ) {
    this.defaultCostCenter = defaultCostCenter ;
}

@Formula(value="(" +
        "SELECT *" +
            " FROM (Select wbs.*" +
                " from T_WORK_BREAKDOWN_STRUCTURE wbs" +
                " LEFT OUTER JOIN T_Company c" +
                    " on wbs.company_id = c.id" +
                " where wbs.sap_code in (select TECA.DEFAULT_WBS_SAP_CODE" + //We shouldn't have to do this this, but whenever I try to call the field DEFAULT_WBS_SAP_CODE direct in the formula, it complains it can't find it
                                        " from T_EMPLOYEE_COMPANY_ASSIGNMENT TECA" +
                                        " where TECA.EMPLOYEE_ID = EMPLOYEE_ID)" +
                    " and wbs.is_blocked_in_sap = 0" +
                    " and wbs.is_deleted_in_sap = 0" +
                " order by wbs.sap_code DESC)" +
        " WHERE ROWNUM = 1"+
        ")")
public WorkBreakdownStructure getDefaultWbs() {
    return defaultWbs;
}
public void setDefaultWbs(WorkBreakdownStructure  defaultWbs) {
    this.defaultWbs = defaultWbs;
}

现在我最初在没有内部选择的情况下直接使用列 DEFAULT_COST_CENTER_SAP_CODE 和 DEFAULT_WBS_SAP_CODE,但是在这两个列上都收到错误无效标识符,所以我想我会尝试使用 ID 来代替引用,但这也是提出无效的标识符。这是hibernate产生的SQL代码:

2016-02-29 09:07:49,810 调试 org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:104) [rw] - 选择 employeeco0_.EMPLOYEE_ID 作为 EMPLOYEE2_33_1_,employeeco0_.COMPANY_ID 作为 COMPANY1_34_1_ , employeeco0_.EMPLOYEE_ID as EMPLOYEE2_34_1_, employeeco0_.COMPANY_ID as COMPANY1_34_0_, employeeco0_.EMPLOYEE_ID as EMPLOYEE2_34_0_, employeeco0_.DEFAULT_COST_CENTER_SAP_CODE as DEFAULT7_34_0_, employeeco0_.DEFAULT_WBS_SAP_CODE as DEFAULT8_34_0_, (SELECT * FROM(Select * from T_COST_CENTER cc where cc.is_blocked_in_sap = 0 and cc. is_deleted_in_sap = 0 and cc.company_id in (SELECT TECA.COMPANY_ID FROM T_EMPLOYEE_COMPANY_ASSIGNMENT TECA WHERE TECA.EMPLOYEE_ID = employeeco0_.EMPLOYEE_ID) and LTRIM((SELECT * FROM (select TECA.DEFAULT_COST_CENTER_SAP_CODE from T_EMPLOYEE_COMPANY_ASSIGNMENT TECA WHERE TECA.EMPLOYEE_ID = employeeco0_.EMPLOYEE_ID) where ROWNUM = 1), '0') = LTRIM(cc.sap_code, '0') order by cc.sap_code DESC) WHERE ROWNUM = 1) as formula2_0_, (SELECT * FROM (从 T_WORK_BREAKDOWN_STRUCTURE wbs LEFT OUTER JOIN T_Company c 中选择 wbs。 .is_deleted_in_sap = 0 order by wbs.sap_code DESC) WHERE ROWNUM = 1) as formula3_0_ from T_EMPLOYEE_COMPANY_ASSIGNMENT employeeco0_ where (employeeco0_.COMPANY_ID in (select c.id from T_COMPANY c where c.is_deleted_in_sap =0)) and employeeco0_.EMPLOYEE_ID=?按员工co0_.COMPANY_ID 订购

2016-02-29 09:07:49,811 TRACE org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:83) [rw] - 绑定参数 [1] 作为 [BIGINT] - 28250

2016-02-29 09:07:49,811 TRACE org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:83) [rw] - 绑定参数 [1] 作为 [BIGINT] - 28250

2016-02-29 09:07:49,811 TRACE org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:83) [rw] - 绑定参数 [1] 作为 [BIGINT] - 28250

2016-02-29 09:07:49,817 WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions(SqlExceptionHelper.java:143) [rw] - SQL 错误:904,SQLState:42000

2016-02-29 09:07:49,817 WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions(SqlExceptionHelper.java:143) [rw] - SQL 错误:904,SQLState:42000

2016-02-29 09:07:49,817 错误 org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions(SqlExceptionHelper.java:144) [rw] - ORA-00904:“EMPLOYEECO0_”。“EMPLOYEE_ID”:无效的标识符

2016-02-29 09:07:49,817 错误 org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions(SqlExceptionHelper.java:144) [rw] - ORA-00904: "EMPLOYEECO0_"."EMPLOYEE_ID": 无效标识符

谁能看出问题出在哪里?这一切对我来说似乎很奇怪......

这是在 Oracle SQL 环境中使用 IntelliJ 完成的。没有公式,这个类可以正常工作

编辑

我已经更新了一个函数的公式,并进行了更多测试,看看我能做什么,我已经掌握了,所以以下工作:

@OneToOne
@JoinColumnsOrFormulas({
        @JoinColumnOrFormula(formula=@JoinFormula("(SELECT * FROM (" +
                "SELECT WBS.ID FROM T_WORK_BREAKDOWN_STRUCTURE WBS" +
                " LEFT OUTER JOIN T_COMPANY c" +
                " ON WBS.COMPANY_ID = C.ID" +
                " WHERE"+
                " WBS.IS_BLOCKED_IN_SAP = 0" +
                " AND WBS.IS_DELETED_IN_SAP = 0" +
                " ORDER BY WBS.SAP_CODE DESC)" +
                "WHERE ROWNUM=1)"))
})
public WorkBreakdownStructure getDefaultWbs() {
    return defaultWbs;
}

但是,一旦我将此行添加到 where 子句:

WBS.SAP_CODE IN (SELECT TECA.DEFAULT_WBS_SAP_CODE FROM T_EMPLOYEE_COMPANY_ASSIGNMENT TECA WHERE TECA.EMPLOYEE_ID = EMPLOYEE_ID)

或者这个:

WBS.SAP_CODE = DEFAULT_WBS_SAP_CODE

由于标识符无效(分别在 EMPLOYEE_ID 和 DEFAULT_WBS_SAP_CODE 上)失败,但这些字段用于它为其填充的属性生成的 SQL 代码中。测试数据库中生成的 SQL 直接有效。生成的工作 SQL 代码如下所示:

select
    employeeco0_.COMPANY_ID as COMPANY1_34_,
    employeeco0_.EMPLOYEE_ID as EMPLOYEE2_34_,
    employeeco0_.DEFAULT_COST_CENTER_SAP_CODE as DEFAULT7_34_,
    employeeco0_.DEFAULT_WBS_SAP_CODE as DEFAULT8_34_,
    (SELECT
        * 
    FROM
        (SELECT
            WBS.ID 
        FROM
            T_WORK_BREAKDOWN_STRUCTURE WBS 
        LEFT OUTER JOIN
            T_COMPANY c 
                ON WBS.COMPANY_ID = C.ID 
        WHERE
            WBS.IS_BLOCKED_IN_SAP = 0 
            AND WBS.IS_DELETED_IN_SAP = 0 
        ORDER BY
            WBS.SAP_CODE DESC)
    WHERE
        ROWNUM=1
    ) as formula9_ 
from
    T_EMPLOYEE_COMPANY_ASSIGNMENT employeeco0_

失败的看起来是这样的:

select
    employeeco0_.COMPANY_ID as COMPANY1_34_,
    employeeco0_.EMPLOYEE_ID as EMPLOYEE2_34_,
    employeeco0_.DEFAULT_COST_CENTER_SAP_CODE as DEFAULT7_34_,
    employeeco0_.DEFAULT_WBS_SAP_CODE as DEFAULT8_34_,
    (SELECT
        * 
    FROM
        (SELECT
            WBS.ID 
        FROM
            T_WORK_BREAKDOWN_STRUCTURE WBS 
        LEFT OUTER JOIN
            T_COMPANY c 
                ON WBS.COMPANY_ID = C.ID 
        WHERE
            WBS.SAP_CODE IN (
                SELECT
                    TECA.DEFAULT_WBS_SAP_CODE 
                FROM
                    T_EMPLOYEE_COMPANY_ASSIGNMENT TECA 
                WHERE
                    TECA.EMPLOYEE_ID = employeeco0_.EMPLOYEE_ID
            ) 
            AND WBS.IS_BLOCKED_IN_SAP = 0 
            AND WBS.IS_DELETED_IN_SAP = 0 
        ORDER BY
            WBS.SAP_CODE DESC)
        WHERE
            ROWNUM=1) as formula9_ 
    from
        T_EMPLOYEE_COMPANY_ASSIGNMENT employeeco0_

或者看起来像这样:

select
    employeeco0_.COMPANY_ID as COMPANY1_34_,
    employeeco0_.EMPLOYEE_ID as EMPLOYEE2_34_,
    employeeco0_.DEFAULT_COST_CENTER_SAP_CODE as DEFAULT7_34_,
    employeeco0_.DEFAULT_WBS_SAP_CODE as DEFAULT8_34_,
    (SELECT
        * 
    FROM
        (SELECT
            WBS.ID 
        FROM
            T_WORK_BREAKDOWN_STRUCTURE WBS 
        LEFT OUTER JOIN
            T_COMPANY c 
                ON WBS.COMPANY_ID = C.ID 
        WHERE
            WBS.SAP_CODE = employeeco0_.DEFAULT_WBS_SAP_CODE 
            AND WBS.IS_BLOCKED_IN_SAP = 0 
            AND WBS.IS_DELETED_IN_SAP = 0 
        ORDER BY
            WBS.SAP_CODE DESC)
    WHERE
        ROWNUM=1
    ) as formula9_ 
from
    T_EMPLOYEE_COMPANY_ASSIGNMENT employeeco0_

然而,在数据库中完成时,它仍然有效(当您将 employeeco0_.EMPLOYEE_ID 或 DEFAULT_WBS_SAP_CODE 替换为有效 ID 时)。希望这次更新有点帮助

【问题讨论】:

    标签: java sql oracle hibernate


    【解决方案1】:

    在使用公式和休眠之前,我会尝试直接在数据库中运行查询,以了解查询的哪一部分是错误的。

    查看您的@Formula,我只看到“选择 *”:您不能不使用公式返回完全托管的实体,就像 @ManyToOne 一样。

    您必须将@Formula 与String 或Interger 一起使用。 @Formula 中的 Select 必须只有一列

    此外,公式是与实体一起获取的,由于查询的复杂性,它会严重影响性能,并且在 90% 的情况下它不会被使用。也许在你的情况下,不使用公式可能是值得的

    【讨论】:

    • 我已经更新了代码,现在它只返回所需实体的 ID,只要我不使用实体或子选择中的任何属性,它就可以工作具有来自实体的属性。至于使用公式以外的其他东西,这是不可能的,我正在重构遗留代码但无法更改数据库,该字段必须手动完成,必须通过实体框架完成
    • 这似乎是问题所在:stackoverflow.com/questions/10092320/…
    【解决方案2】:

    问题是由于 Oracle SQL 无法引用在内部查询的外部查询中声明的列。我必须重新考虑并重做查询,这样我就不需要在内部查询中引用字段 DEFAULT_WBS_SAP_CODE 或 EMPLOYEE_ID

    【讨论】:

      猜你喜欢
      • 2014-11-28
      • 2011-02-14
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 2012-04-16
      • 2014-09-27
      • 2015-09-23
      相关资源
      最近更新 更多