添加带有 JPA 注释的现有方法签名的接口会破坏 Eclipselink

Posted

技术标签:

【中文标题】添加带有 JPA 注释的现有方法签名的接口会破坏 Eclipselink【英文标题】:Adding interface with existing method signature that is annotated with JPA breaks Eclipselink 【发布时间】:2015-11-27 12:13:32 【问题描述】:

长期以来,我有以下具有持久性的类使用JPA和Eclipselink作为持久性提供者,它们被成功持久化和查询。

ProductKeyImpl:

@Entity
@Table(name = "PRODUCT_KEY")
@Access(PROPERTY)
public class ProductKeyImpl implements ProductKey 
    ...

派生类 SomeProductKeyImpl:

@Entity
public class SomeProductKeyImpl
    extends ProductKeyImpl
    implements SomeProductKey 
    private String accoStockCode = null;
    ....
    @Column(name = "KEY_3")
    public String getAccoStockCode() 
        return this.accoStockCode;
    

实现接口SomeProductKey:

public interface SomeProductKey extends ProductKey 
    String getAccoStockCode();

在重构期间,方法 getAccoStockCode() 被移动到由 SomeProductKey 实现的新接口 HasAccoStockCode

public interface HasAccoStockCode 
    String getAccoStockCode();

public interface SomeProductKey extends ProductKey, HasAccoStockCode 
    // getAccoStockCode() removed

自此更改以来,查询失败,因为显然 Eclipselink 不仅将 accoStockCode 到 KEY_3 的带注释映射添加到 SQL,而且还添加了来自 HasAccoStockCode 的 getAccoStockCode 方法的默认映射:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: ORA-00904: "ACCOSTOCKCODE": ungültiger Bezeichner

Error Code: 904
Call: SELECT ..., ACCOSTOCKCODE, KEY_3 ... FROM PRODUCT_KEY WHERE (ID = ?)

正确的选择语句不应包含 ACCOSTOCKCODE,因为该属性映射到 KEY_3

我在 Eclipselink 2.4.2 上也看到了相同的行为。万一重要,代码在 Java 7 上的 Weblogic 12.1.2 上运行。

除了恢复重构之外我还能做什么?

在@Chris 提问后编辑: 如果我从接口中删除 getAccoStockCode() ,仍然会发生相同的错误(对我来说出乎意料......)。 您的问题将我引向另一个测试用例。 JPQL

SELECT a FROM SomeProductKeyImpl a WHERE a.oid = :id

用 SQL 执行就好了

SELECT ID, PRODUCT_KEY_SUBCLASS_CODE, TIME_STAMP, KEY_3, KEY_4, KEY_2, KEY_1 FROM VRPBOOKING.PRODUCT_KEY WHERE ((ID = ?) AND (PRODUCT_KEY_SUBCLASS_CODE = ?))
bind => [123, SPK]

如果我使用 JPQL 查询超类

SELECT a FROM ProductKeyImpl a WHERE a.oid = :id

生成的SQL是

SELECT ID, PRODUCT_KEY_SUBCLASS_CODE, TIME_STAMP, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, ACCOSTOCKCODE FROM VRPBOOKING.PRODUCT_KEY WHERE (ID = ?)
bind => [123]

失败了。

【问题讨论】:

只是为了澄清,如果从所有接口中删除 getAccoStockCode() 方法,这是否有效?如果您使用 JPQL 中的 accoStockCode 执行查询,会生成什么? 【参考方案1】:

问题解决了,其实不是 Eclipselink 的问题,而是开发者的问题。我们有另一个类 SomeOtherProductKeyImpl 已更改为实现接口,但没有 getAccoStockCode() 的注释。注释后,一切正常。 再次感谢 @Chris 提出的问题导致解决方案。

【讨论】:

以上是关于添加带有 JPA 注释的现有方法签名的接口会破坏 Eclipselink的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA 审计不适用于带有 @Modifying 注释的 JpaRepository 更新方法,为啥?

[ SSH框架 ] Hibernate框架学习之四(JPA)

为后代设计接口

在不破坏现有基类的情况下向具有许多派生类的抽象基类添加新方法

带有谷歌签名的安卓应用发布

Spring JPA事务通过多种方法