2017-01-04 124 views
0

難住了,徹底難倒了複合主鍵...春數據JPA:無法保存實體包含外鍵

假設兩個實體,父母與子女,與許多子實體父母一方。 Parent的主鍵是java.util.UUID類型,而Child的主鍵是Parent的UUID和序列號的組合。

短的問題是,當我嘗試保存使用childRepository.save(child)一個新的孩子,我得到以下異常:

造成的:java.lang.IllegalArgumentException異常:無法轉換 類型[值COM .package.entities.ParentEntity $$ _ jvst149_0]爲所需類型 屬性'parent'的[java.util.UUID]:PropertyEditor [org.springframework.beans.propertyeditors.UUIDEditor]返回 不適當的值爲 [com。 package.entities.ParentEntity _ $$ _ jvst149_0]

請看下面我的課程。最好的,我可以告訴我正確遵循了JPA規範,所以我不知道如果這是在Spring Data JPA一個錯誤,也許具體到UUID類型ID(類似的事情以前也發生過,看DATAJPA-269

注意我用的spring-boot-starter-data-jpa 1.4.1.RELEASE

Parent.java:

@Entity 
@Table(name = "parent") 
public class Parent implements Serializable { 

    @Id 
    @GeneratedValue(generator = "uuid") 
    @GenericGenerator(name = "uuid", strategy = "uuid2") 
    private UUID id; 

    //...other fields, getters + setters... 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     Parent that = (Parent) o; 
     return Objects.equals(id, that.id); 
    } 

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

Child.java

@Entity 
@Table(name = "child") 
@IdClass(ChildKey.class) 
public class Child implements Serializable { 

    @Id 
    @ManyToOne 
    @JoinColumn(name = "parent_id", referencedColumnName = "id", insertable = false, updatable = false) 
    private Parent parent; 
    @Id 
    private Integer seqNum; 

    //...other fields, getters + setters... 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     Child that = (Child) o; 
     return Objects.equals(parent, that.parent) && 
       Objects.equals(seqNum, that.seqNum); 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hash(parent, seqNum); 
    } 
} 

ChildKey的.class

public class ChildKey implements Serializable { 

    private UUID parent; 
    private Integer seqNum; 

    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     ChildKey that = (ChildKey) o; 
     return Objects.equals(parent, that.parent) && 
       Objects.equals(seqNum, that.seqNum); 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hash(parent, seqNum); 
    } 
} 

ParentRepository.java

@Repository 
public interface ParentRepository extends JpaRepository<Parent, UUID> { 
} 

ChildRepository.java

@Repository 
public interface ChildRepository extends CrudRepository<Child, ChildKey> { 
} 

最後,代碼我執行:

@Transactional 
public void createChild(Parent parent) { 
    // needed to do this to get over "detached entity passed to persist" 
    parent = parentRepository.getOne(parent.getId()); 
    child = new Child(); 
    child.setParent(parent); 
    child.setSeqNum(1); 
    childRepository.save(child); 
} 

回答

0

在許多到一你的孩子實體擁有它的關係自己的ID和來自父實體的ID是FK不是PK的一部分。 Example

+0

謝謝 - 我很欣賞答案,但我不認爲我會遵循。在我使用過的每個RDBMS中,我從來沒有遇到過一個兒童的主鍵由外鍵組成的問題 - 事實上,這是規範化數據庫的常用策略。 – Jpnh

0

在發佈此問題後的幾個月中,我還沒有找到合適的答案。我不幸得了不使用@ManyToOne解決這個問題,而不是僅僅通過UUID引用父:

public class Child implements Serializable { 

    @Id 
    private UUID parentId; 
    @Id 
    private Integer seqNum; 

我離開JPA無知的外鍵,只是讓數據庫拋出一個錯誤,我應該違​​反參考完整性。

0

你需要改變你的ChildKey類:

public class ChildKey implements Serializable { 

    private Parent parent; // <-- Parent type instead of UUID 
    private Integer seqNum; 
    ... 

UPD:我讀JPA規範。並明白這是不正確的。但它適用於我的情況。

+0

有趣!謝謝。我不再在啓發這個問題的代碼基礎上工作,但下次我嘗試做這樣的事情時,我會嘗試它。 – Jpnh