2017-06-22 78 views
1

可以說我有兩個對象,一個是用戶對象,另一個是狀態對象。國家對象基本上是美國的50個州,所以它不必改變。然而,用戶對象具有用戶所在的國家集合。所以像這樣的:將對象A中的對象添加到對象B中而不創建新對象? HIBERNATE

@Entity 
@Table(name="tbl_users") 
class User { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name="id", unique=true, nullable = false) 
    private int id; 

    @Column(name="user_name") 
    private String name; 

    @OneToMany(targetEntity=State.class, orphanRemoval = false) 
    @Column(name="states") 
    private Collection<State> states; 

    //getters and setters 
} 

和美國實體看起來是這樣的:

@Entity 
@Table(name="tbl_states") 
class State { 

    @Id 
    @Column(name="id", unique=true, nullable=false) 
    private int id; 

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

    // getters and setters 
} 

代碼添加用戶(使用Hibernate):

public int addUser(User user) { 
    em.persist(user); 
    em.flush(); 
    return user.getId(); 
} 

代碼通過ID獲取狀態:

public State getStateById(int id) { 
    return em.createQuery("SELECT s FROM State s WHERE s.id =:id, State.class) 
      .setParameter("id", id) 
      .getSingleResult(); 
} 

但是當我嘗試創建一個用戶,並選擇幾個州,我得到一個PSQLException:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_g6pr701i2pcq7400xrlb0hns" 
2017-06-21T22:54:35.959991+00:00 app[web.1]: Detail: Key (states_id)=(5) already exists. 

我試圖尋找了級聯方法,看看我是否可以使用任意的,但Cascade.MERGE和Cascade.PERSIST似乎做同樣的事情,其餘的我不認爲我需要(REMOVE,DETACH等)。我的問題是: 如何在沒有該錯誤的情況下向User對象添加狀態?

+0

在將它們添加到用戶對象之前,如何檢索狀態對象? –

+0

@Aassass我爲每個做了一個getStateById(),它將狀態Object返回到數組列表中,然後使用setter方法將該數組列表添加到用戶中 – Aria

+0

您可以提供處理保存方法的完整代碼。爲什麼你的collection屬性之上有一個@Column,你不需要這個,我想你有一個支持關係的表user_state? –

回答

1

此代碼:

class Example { 

    @Test 
    public void workingTest() { 
     EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPU"); 
     EntityManager em = emf.createEntityManager(); 

     // Creating three states 
     State alabama = new State(state: 'Alabama'); 
     State louisiana = new State(state: 'Louisiana'); 
     State texas = new State(state: 'Texas'); 
     em.getTransaction().begin(); 
     em.persist(alabama); 
     em.persist(louisiana); 
     em.persist(texas); 
     em.getTransaction().commit(); 

     List<State> states = em.createQuery('FROM State').getResultList(); 

     // Assert only three states on DB 
     assert states.size() == 3; 

     User userFromAlabama = new User(); 
     User userFromAlabamaAndTexas = new User(); 

     em.getTransaction().begin(); 
     State alabamaFromDB = em.find(State, alabama.getId()); 
     State texasFromDB = em.find(State, texas.getId()); 
     userFromAlabama.getStates().add(alabamaFromDB); 
     userFromAlabamaAndTexas.getStates().add(alabamaFromDB); 
     userFromAlabamaAndTexas.getStates().add(texasFromDB); 

     em.persist(userFromAlabama); 
     em.persist(userFromAlabamaAndTexas); 
     em.getTransaction().commit(); 

     states = em.createQuery('FROM State').getResultList(); 

     // Assert only three states on DB again 
     assert states.size() == 3; 

     // Assert one user 
     User userFromDB = em.find(User, userFromAlabama.getId()); 
     assert userFromDB.getStates().size() == 1; 

     userFromDB = em.find(User, userFromAlabamaAndTexas.getId()); 
     assert userFromDB.getStates().size() == 2; 
    } 
} 

@Entity 
@Table(name="tbl_users") 
class User { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id 

    @Column(name="user_name") 
    private String name 

    @ManyToMany 
    private Collection<State> states = Lists.newArrayList() 

    // Getters and setters 
} 

@Entity 
@Table(name="tbl_states") 
class State { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private int id; 

    @Column(name="state") 
    private String state; 
    // Getters and setters 
} 

你應該改變你的映射@ManyToMany!

而且你必須對DB 3個表是這樣的: TBL_USERS,TBL_STATES和TBL_USERS_TBL_STATES

的TBL_USERS_TBL_STATES表是當一個屬性與@ManyToMany註解是Hibernate使用默認的表名。如果要更改TBL_USERS_TBL_STATES的表名,也可以使用@JoinTable註釋。請參閱文檔here

使用此配置,您應該能夠從數據庫獲取狀態,將其添加到新用戶,然後保留它。我做了一個單元測試,它的工作原理!

+0

你是說要刪除到@OneToMany配置? – Aria

+0

是的,因爲你不需要它。您真正需要的是確保數據庫中存在中間表「TBL_USERS_TBL_STATES」。 Hibernate將使用這個表來映射用戶的狀態(狀態集合)! – rafaelim

+0

services_id?這個領域在哪裏? – rafaelim

0

在你的情況下,可能會更好地使用manytomany協會與許多tomany hibernate不生成unicity約束。

對於onetoMany,Hibernate自動生成方案行爲有點奇怪,但是您可以使用此解決方法。

試試這個:

@ManyToMany 
@JoinTable(name = "user_state") 
private List<State> states; 
+0

這不起作用,它不停地創建多個用戶一次?如果我選擇2個州,它會創建2個具有相同詳細信息的用戶(ID除外) – Aria

+0

它應該工作,也許您的保存邏輯不正確,請添加您的所有業務代碼的發佈詳情,我需要整個圖片。從用戶實例化或加載直到持久化並刷新到數據庫包含圍繞adduser方法的代碼。 –

相關問題