2014-10-30 163 views
0

我有JPA映射一個簡單的類:JPA映射基本的類繼承

@Entity 
@Table(name = "SPONSOR") 
public class Sponsor extends PersistableBusinessObjectBase implements SponsorContract { 

@PortableSequenceGenerator(name = "SEQ_SPONSOR_CODE") 
@GeneratedValue(generator = "SEQ_SPONSOR_CODE") 
@Id 
@Column(name = "SPONSOR_CODE") 
private String sponsorCode; 

@Column(name = "ACRONYM") 
private String acronym; 

@Column(name = "AUDIT_REPORT_SENT_FOR_FY") 
private String auditReportSentForFy; 

@Column(name = "CAGE_NUMBER") 
private String cageNumber; 

@Column(name = "COUNTRY_CODE") 
private String countryCode; 

@Column(name = "DODAC_NUMBER") 
private String dodacNumber; 

@Column(name = "DUN_AND_BRADSTREET_NUMBER") 
private String dunAndBradstreetNumber; 

@Column(name = "DUNS_PLUS_FOUR_NUMBER") 
private String dunsPlusFourNumber; 

@Column(name = "OWNED_BY_UNIT") 
private String ownedByUnit; 

@Column(name = "POSTAL_CODE") 
private String postalCode; 

@Column(name = "ROLODEX_ID") 
private Integer rolodexId; 

@Column(name = "SPONSOR_NAME") 
private String sponsorName; 

@Column(name = "SPONSOR_TYPE_CODE") 
private String sponsorTypeCode; 

@Column(name = "STATE") 
private String state; 

@Column(name = "CREATE_USER") 
private String createUser; 

@Column(name = "ACTV_IND") 
@Convert(converter = BooleanYNConverter.class) 
private boolean active; 

@ManyToOne(cascade = { CascadeType.REFRESH }) 
@JoinColumn(name = "SPONSOR_TYPE_CODE", referencedColumnName = "SPONSOR_TYPE_CODE", insertable = false, updatable = false) 
private SponsorType sponsorType; 

@ManyToOne(cascade = { CascadeType.REFRESH }) 
@JoinColumn(name = "OWNED_BY_UNIT", referencedColumnName = "UNIT_NUMBER", insertable = false, updatable = false) 
private Unit unit; 

@ManyToOne(cascade = { CascadeType.REFRESH }) 
@JoinColumn(name = "ROLODEX_ID", referencedColumnName = "ROLODEX_ID", insertable = false, updatable = false) 
private Rolodex rolodex; 
.... 

我已經延長該類成一個非常簡單的類

@Entity 
public class SponsorMaintainableBo extends Sponsor { 
} 

這正是我需要的SponsorMaintainableBo 。它是贊助商的副本,並且與贊助商從同一張表中讀取。這是我們的查詢框架所需要的,它是通過一些xml文檔控制的,並且需要成爲我正在做的一個單獨的對象。我們需要SponsorMaintainableBo來插入查詢/維護框架,以獲取我們不希望在主父文檔中定製的詳細信息。當我嘗試使用SponsorMaintainableBo,我得到以下錯誤:

org.springframework.orm.jpa.JpaSystemException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'DTYPE' in 'field list' 
Error Code: 1054 
Call: SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ? 
bind => [3 parameters bound] 
Query: ReadAllQuery(referenceClass=SponsorMaintainableBo sql="SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?"); nested exception is javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'DTYPE' in 'field list' 
Error Code: 1054 
Call: SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ? 
bind => [3 parameters bound] 
Query: ReadAllQuery(referenceClass=SponsorMaintainableBo sql="SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?") 
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321) 
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:120) 

我不知道映射子類,並繼承所有的JPA映射的最佳途徑。請指教。

+0

請提供有關'SponsorMaintainableBo'的更多詳細信息。它不清楚它有多少額外的數據庫字段,是否爲其添加了另一個表以及它用於什麼。 – jbx 2014-10-30 14:47:34

+0

向我們展示ReadAllQuery – bigGuy 2014-10-30 14:48:15

+0

我用完全不同的方式解決了這個問題。我將通過注意清除JPA相關問題的正確答案來解決此問題。 – Jay 2014-11-20 13:35:19

回答

3

Here約爲JPA實體繼承的一些信息。

你必須在你的實體配置的繼承,這是不夠的只是進行擴展的類。如果你想在一個單獨的表中有SponsorMaintainableBo,那麼用@Inheritance(strategy=TABLE_PER_CLASS)註釋Sponsor實體。在線有很多示例用於配置不同類型的繼承。

public enum InheritanceType { 
    SINGLE_TABLE, 
    JOINED, 
    TABLE_PER_CLASS 
}; 

Unknown column 'DTYPE' in 'field list'意味着SINGLE_TABLE是默認的繼承類型,並且您的JPA提供商正在尋找(默認命名)在目標表列DTYPE,以確定該實體的確切類型。

+0

+1爲DTYPE鑑別器列的默認名稱 – jbx 2014-10-30 14:59:07

0

您還沒有指定的你有SponsorMaintainableBo所以其難度怎麼明白你在那裏的細節。

你沒有完全擴展以正確的方式你的實體。你需要給提示你將如何擴展原始數據庫中的表(一切都在同一個表束身,被稱爲SINGLE_TABLE?用一到一個參考的新表稱爲JOINED?表與副本新的字段被稱爲TABLE_PER_CLASS?)

您應該看看http://en.wikibooks.org/wiki/Java_Persistence/Inheritance以瞭解如何正確執行此操作。

UPDATE

雖然它仍然不是很清楚什麼SponsorMaintainableBO實際上是幹什麼的,從你加入我懷疑的原因是,你在這裏使用了錯誤的設計模式的細節。如果擴展JPA實體Bean,系統會希望你這樣做來添加額外的字段,因此它還添加了區分數據庫中兩個實體(超類和子類)的機制。默認情況下,如@Predrag所示,它需要一個名爲DTYPE的字段到表中,以便可以確定行是否是超類或子類的實例(繼承不是標準SQL所支持的)。還有其他可供使用的機制,例如完全獨立的表,或者通過外鍵將第2表連接在一起的第2表,僅添加由子類添加的字段。

從你所說的話

現在,你似乎並沒有做(或需要)的任何現象。如果我的理解正確,你將重載Entity bean的責任,並期望你的框架具有進一步的行爲。 Entity Beans被設計爲Beans,即數據的載體。如果您對它們進行了擴展,那麼JPA會明白,您正在這樣做是出於某種原因,添加更多數據(即更多字段)。你似乎想要的是你的實體的包裝,以便它也可以插入到你的框架中。這種方式兩個問題都保持分開,但仍然捆綁在一起。

我不知道你的框架期望從SponsorMaintainableBo期待什麼,但我的傾向是你應該使用不同的方法。而不是讓SponsorMaintainableBo延長Sponsor你或許應該把的SponsorSponsorMaintainableBo從而改變從SponsorMaintainableBo-is-A-SponsorSponsorMaintainableBo都具有一個-A-Sponsor的關係的實例。你可以做Sponsor構造函數的參數和不可變的這樣,如果你想這兩種情況下,以絕對耦合:如果上面是不夠的

public class SponsorMaintainableBo 
{ 
    private final Sponsor sponsor; 

    public SponsorMaintainableBo(Sponsor sponsor) 
    { 
     this.sponsor = sponsor; 
    } 

    public Sponsor getSponsor() 
    { 
     return this.sponsor; 
    } 

    //... rest of the methods expected by the framework 
} 

,並且框架預計SponsorMaintainableBo一些領域都已普及與Sponsor你應該使用Decorator pattern。我相信你已經在SponsorContract有這個所以最有可能你需要做的是:

public class SponsorMaintainableBo implements SponsorContract 
{ 
    private final Sponsor sponsor; 

    public SponsorMaintainableBo(Sponsor sponsor) 
    { 
     this.sponsor = sponsor; 
    } 

    public Sponsor getSponsor() 
    { 
     return this.sponsor; 
    } 

    //... rest of the methods specified by `SponsorContract` 

    //... rest of the methods expected by the framework 
} 

通過SponsorContract所需的方法只是委託函數調用底層Sponsor實例。 (請注意,完整的裝飾模式旨在將多個實例鏈接在一起,因此它會將SponsorContract sponsor而不是Sponsor sponsor添加到您的SponsorMaintainableBo,這樣您甚至可以將其他行爲鏈接到您的實體周圍,但我認爲您不需要這種複雜程度)

+0

我編輯我的問題,希望現在更清楚。 – Jay 2014-10-30 16:51:48

+0

你可以給一些關於什麼SponsorMaintainableBO正在做一些示例代碼的更多信息?我懷疑你在這裏使用了錯誤的模式,但在我說之前我需要知道更多。 – jbx 2014-10-30 23:38:33