2017-08-29 72 views
4

我目前正在爲遺留數據庫(大量複合鍵和單列鍵)定義JPA實體。我創建了以下實體超:JPA(Hibernate):在通用@MappedSuperclass中使用@EmbeddedId時出錯

@MappedSuperclass 
public abstract class AbstractEntity<ID extends Serializable> { 
    public abstract ID getId(); 
    public abstract void setId(ID id); 
} 

然後對組合鍵的超類(以及長期主鍵的超類,不在此列):

@MappedSuperclass 
public abstract class AbstractEmbeddedIdEntity<ID extends Serializable> extends AbstractEntity<ID> { 
    @EmbeddedId 
    private ID id; 

    public AbstractEmbeddedIdEntity() { 
     id = newId(); 
    } 

    @Override 
    public ID getId() { 
     return id; 
    } 

    @Override 
    public void setId(ID id) { 
     this.id = id; 
    } 

    protected abstract ID newId(); 
} 

最後具體的實體,如這樣的:

@Entity 
@Table(name = "firstEntity") 
public class FirstEntity extends AbstractEmbeddedIdEntity<FirstEntityId> { 

    public FirstEntity() { 
    } 

    @Embeddable 
    public static class FirstEntityId implements Serializable { 
     @Column(name = "firstId") 
     private String firstId; 

     public FirstEntityId() { 
     } 

     @Override 
     public boolean equals(Object obj) { 
      if (obj == this) { 
       return true; 
      } 
      if (!(obj instanceof FirstEntityId)) { 
       return false; 
      } 
      FirstEntityId other = (FirstEntityId) obj; 
      return 
        Objects.equals(firstId, other.firstId); 
     } 

     @Override 
     public int hashCode() { 
      return Objects.hash(firstId); 
     } 
    } 

    @Override 
    protected FirstEntityId newId() { 
     return new FirstEntityId(); 
    } 
} 

現在的問題是,如果我有多個實體這樣並嘗試訪問一個實體(當前Spring引導,例如的ID屬性),拋出一個異常:

java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [firstId] on this ManagedType [unknown] 

我已經調試這一點,並發現,在休眠,元我所有的實體映射到同一MappedSupperclass實例。在應用程序啓動期間,由newId()返回的@EmbeddedId被設置爲MappedSupper類,覆蓋前一個實體的ID。所以最後,所有實體都映射到相同的MappedSupper類,但MappedSupper類只有最後一個實體的@EmbeddedId

在上例中,訪問ID屬性失敗,因爲最後一個實體的@EmbeddedId沒有名爲「firstId」的屬性(它已被最後一個實體的ID屬性覆蓋)。

現在我想知道如果我的方法是錯誤的,如果我失去了一些東西,或者這可能是一個與休眠問題?

使用彈簧靴的完整示例available on github。以mvn spring-boot:run運行。

+0

我認爲在涉及到JPA/Hibernate映射時最好不要使用任何抽象類,除非涉及到超類,它的繼承含義。事實上,'@ MappedSuperclass'用於繼承,因此意味着擴展它的不同類之間的巨大鏈接。 你可能應該用最簡單的方法逐一映射它們,所以它們與你的AbstractEntity類沒有關係。 – DamCx

+0

你的意思是'我所有的實體指向他們的MappedSupperclass的同一個實例'? Java中沒有'指向普通超類對象的指針'。另外,如果我是你,我會避免使用內部類作爲可嵌入的 – crizzis

+0

@crizzis:我已更新我的問題並修復了不正確的部分,謝謝指出。實際上,hibernate元模型將我所有的實體映射到相同的MappedSupperclass實例。另外,爲什麼你會避免使用內部類作爲嵌入式? – Dominic

回答

0

這看起來像是一個在休眠狀態下的bug,因此我在hibernate bug tracker中創建了一張票。 作爲一種解決方法,我現在在concreate實體類中定義ID屬性(@EmbeddedId),而不是抽象超類。

相關問題