2017-03-09 61 views
0

我有實體FooDetails,它有兩個領域的關係:客戶和位置的列表。客戶具有地址(@OneToOne單向映射),並且位置也具有使用@OneToOne映射的地址。休眠 - 從多個領域同一個實體

它發生在地址客戶和位置是相同的。所有這些對象來自遠程服務,我手動將ID從遠程對象放入實體中,然後再保存。映射如下所示:

@Entity 
@Table(name = "FOO") 
public class FooDetails { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private long id; 

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
    @JoinColumn(name = "customer_id") 
    private Customer customer; 

    @OneToMany(cascade = CascadeType.ALL) 
    @JoinColumn(name = "details_id") 
    private Set<Location> locationList; 
... 
} 

@Entity 
@Table(name = "CUSTOMER") 
public class Customer { 

    @Id 
    @Column(name = "customer_id", unique = true) 
    private long customerId; 

    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name = "address_id") 
    private Address address; 
... 
} 

@Entity 
@Table(name = "LOCATION") 
public class Location { 

    @Id 
    @Column(name = "location_id", unique = true) 
    private long locationId; 

    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name = "address_id") 
    private Address address; 
... 
} 

@Entity 
@Table(name = "ADDRESS") 
public class Address{ 

    @Id 
    @Column(name = "address_id") 
    private long addressId; 
    ... 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (!(o instanceof StawareAddress)) return false; 

     StawareAddress that = (StawareAddress) o; 

     return addressId == that.addressId; 
    } 

    @Override 
    public int hashCode() { 
     return (int) (addressId^(addressId >>> 32)); 
    } 
} 

當我從webservice收到整個FooDetails對象時,我嘗試將它保存到本地數據庫。

如果數據庫是乾淨的(沒有地址保存至今),與WS正確的ID地址保存。如果已經有一個帶有這個ID的地址,Hibernate會嘗試將新的一個插入到數據庫中,並且由於addressId上的唯一約束而出現錯誤。

我使用Spring JPA的數據保存實體(save()方法)。

我錯過了什麼明顯的實體映射的問題?

回答

1

我真的不鼓勵使用CascadeType.ALL這裏和手動處理。

public void saveFoodetails(FooDetails fooDetails) { 
    Address address = addressRepository.find(fooDetails.getAddress().getId()); 
    if (address != null) { 
    // perhaps you update address with data from fooDetails.getAddress() 
    addressRepository.save(address); 
    // associate attached address instance with fooDetails now. 
    fooDetails.setAddress(address); 
    } 
    else { 
    // save the new incoming address contained in FooDetails 
    addressRepository.save(fooDetails.getAddress()); 
    } 
    // now save/update FooDetails 
    fooDetailsRepository.save(fooDetails);   
} 
+0

這是我知道的解決方案之一,但我想避免 - 我相信Hibernate應該處理它。傳遞給save()的分離實體具有基於始終存在的主鍵(與數據庫中存在的相同)的正確hashcode&equals。爲什麼級聯不起作用? – mdziob

+0

哈希碼/等於與此無關。您正在FooDetails上執行PERSIST操作,這就是級聯到子關係Address的原因。顯然你不能使用相同的標識符來保存一個新的地址;不過,你可以合併。但是,再次,這不是你在串聯:)。 – Naros

+0

我不知道我是否正確理解你。正如我所提到的,我使用了spring數據jpa中的save()方法,該方法檢查傳遞的實體是否具有ID - 如果是,則調用合併(http://stackoverflow.com/questions/16559407/spring-data中的代碼片段-jpa保存新實體引用現有一)。所以合併不會級聯? – mdziob