2015-04-06 68 views
0

我正在使用EJB3.2和JPA 2.1。 在我的應用我有這些實體(簡稱):如何正確管理jpa雙向關係?

@Entity 
public class Festival 
{ 
    int Id; 
    String name; 
    ... 
    @ManyToOne 
    @JoinColumn(name = "merchant", referencedColumnName = "Id") 
    Merchant merchant; 
} 

@Entity 
public class Merchant 
{ 
    int Id; 
    String name; 

    ... 

    @ManyToOne 
    @JoinColumn(name = "category", referencedColumnName = "Id") 
    Category category; 

    @ManyToOne 
    @JoinColumn(name = "city", referencedColumnName = "Id") 
    City city; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "festival") 
    List<Festival> festivalList; 
} 

@Entity 
public class Category 
{ 
    int Id; 
    String name; 
    ... 
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant") 
    List<Merchant> merchantList; 
} 

@Entity 
public class City 
{ 
    int Id; 
    String name; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant") 
    List<Merchant> merchantList; 
} 

因此,(節日,商家)有一個像(商人,類別)和(商人,市)的雙向關係

問題當我刪除或更改商家時,仍然在類別merchantList和cities merchantList中有未更改的副本!等等..

我應該如何管理這些變化?!爲什麼JPA不會自己更改其他副本?它不會增加錯誤的複製風險?!

+0

您不讓JPA知道雙向關係。它可以通過「mappedBy」屬性完成。請閱讀文章:http://examples.javacodegeeks.com/enterprise-java/jpa/one-to-many-bidirectional-mapping-in-jpa/ – VirtualLogic 2015-04-06 13:37:05

+0

親愛的@Shanu,我的問題不在於此。我在這裏簡單地寫了代碼,真正的代碼有這個屬性,但是爲了解析,我也會在編輯時將它們寫在這裏。 – 2015-04-06 13:39:03

+1

是的,請提供模式代碼片段,以提供具體的幫助。 – VirtualLogic 2015-04-06 13:41:27

回答

1

JPA將像常規java對象一樣對待實體,並且不會爲您維護關係 - 應用程序負責確保雙向關係的雙方在更改一方時保持同步。因此,當您從商戶取消引用城市時,必須從城市的merchantList中刪除對商戶的引用,然後在必要時進行合併。

否則,通過Java對象的數據視圖將與數據庫不同步,直到從數據庫刷新對象。您可以衡量保持雙方同步或刷新時的價值和成本,或者甚至不映射非擁有方,並根據實體確定您的應用程序更適合您的應用程序。

+0

它是一個很好的模式,改變我的DAO來監督我的CRUD,當一個對象發生變化時,將它傳播給它在相關實體中的引用?例如,當我調用「em.update(merchant)」時,它立即調用merchant.getCity()。getMerchantList()。find(merchant.getId())= merchant? – 2015-04-07 05:36:20

+2

@HamidAdldoost當你簡單地更新實體中的某些字段時,你不必這樣做,JPA保證在存儲器中只有一個具有相同ID的實體的實例存在(當然是一個管理實例)。這意味着如果您多次執行'em.find(MyEntity.class,someId)',它將始終返回相同的確切對象。您只需在更改實體之間的關係時進行刷新。 – 2015-04-07 07:46:11

1

我覺得從「Java持久性使用Hibernate」(第261)由Christian Bauer和加文·金這句話可能對您有用:

相反,EJB 2.0 CMR,Hibernate和JPA協會都 本質上是單向的。

因此,從商家到類別的關聯不同於從類別到商家的關聯,您需要分別管理它們。

編輯: 我調整您最初的bean的配置看,它應該:(當然,你將會選擇一種合適的主鍵生成策略)

@Entity 
public class Festival 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    int Id; 
    String name; 

    @ManyToOne(cascade=CascadeType.ALL) 
    @JoinColumn(name = "merchant") 
    Merchant merchant; 
} 
@Entity 
public class Merchant 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    int Id; 
    String name; 

    @ManyToOne 
    @JoinColumn(name = "category") 
    Category category; 

    @ManyToOne 
    @JoinColumn(name = "city") 
    City city; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant") 
    List<Festival> festivalList; 
} 
@Entity 
public class Category 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    int Id; 
    String name; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "category") 
    List<Merchant> merchantList; 
} 
@Entity 
public class City 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    int Id; 
    String name; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "city") 
    List<Merchant> merchantList; 
} 
+0

這是否意味着當我更改,添加或刪除商家時,我應該自己更新city.merchantList和category.merchantList?模型如此複雜時怎麼樣?不是很髒嗎? – 2015-04-06 13:47:08

+0

當您更改商家或添加新商戶時,您需要重新加載商家的城市(類別)列表。 – 2015-04-06 14:04:26

+0

你是什麼意思的「重新加載」?它是否意味着「em.refresh(city)」? – 2015-04-06 14:10:03

1

之前,請務必堅持(商家)調用categories.getMerchantList()。

+0

我已經做到了,但仍然不會更新category.getMerchantList()的前一個值,並且在商家本身沒問題的情況下調用它時會得到錯誤的數據! – 2015-04-06 13:52:23