2017-06-22 12 views
1

2つのオブジェクトがあるとしましょう.1つはUserオブジェクトで、もう1つはStateオブジェクトです。状態オブジェクトは、基本的にアメリカの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 
} 

コード(休止状態を使用して)ユーザーを追加する:idで状態を取得するための

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

コード:

だから、このような
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は同じことを行うように見えます残りの部分は私が必要と思わない(削除、デタッチなど)。私の質問は次のとおりです: エラーを発生させずにユーザーオブジェクトに状態を追加するにはどうすればよいですか?

+0

Stateオブジェクトをユーザーオブジェクトに追加する前に、それらを取得するにはどうすればよいですか? –

+0

@AbassAそれぞれに対してgetStateById()を実行し、状態オブジェクトを配列リストに返し、setterメソッドを使用して配列リストをユーザーに追加します – Aria

+0

保存メソッドを処理する完全なコードを提供できますか。なぜあなたはあなたのコレクション属性の上に@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はこのテーブルを使用してユーザの状態をマッピングします(statesコレクション)! – rafaelim

+0

services_id?このフィールドはどこですか? – rafaelim

0

あなたのケースでは、manytomanyの関連付けを使用する方がよいかもしれません。多くの場合、hibernateはunicity制約を生成しません。

Hibernate自動生成スキームの動作は、onetoManyで少し奇妙ですが、この回避策を使用できます。

はこれを試してみてください:

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

これはうまくいかず、すぐに? 2州を選択した場合と同じように、同じ情報(ID以外)を持つ2人のユーザーが作成されます。 – Aria

+0

保存ロジックが正しくない可能性があります。あなたのビジネスコードの詳細を投稿してください。ユーザのインス​​タンス化またはロードから、永続化およびフラッシュするまで、adduserメソッドのまわりのコードを含むデータベース。 –

関連する問題