1

私は問題を抱えており、この問題を克服するためにあなたの助けが必要です。うまくいけば、このトレッドが同様の問題のリファレンスになるかもしれません…</ p>

私の最小化されたビジネスモデルには、ユーザーとタイトルがあります。タイトルは最初に作成する必要があり、多くのユーザーに割り当てることができます。ユーザーは同じタイトルを共有できます。したがって、@ ManyToMany関係を持つUserとTitleという2つのエンティティを作成し、Titleがこの関係を所有する必要があると判断しました。さらに、この例を実行するためのUnitTestがあります。

ユーザーエンティティ

public class User {

    Long id;
    String name;
    Set<Title> titles = new HashSet<Title>();

    @Id
    @GeneratedValue
    @Column(name = "id")    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    /*============ Approach1 ============*/
//  @ManyToMany(mappedBy = "users")
    /*============ Approach2 ============*/
//  @ManyToMany
    /*============ Approach3 ============*/
    @ManyToMany
    @JoinTable( name = "tb_title_user",
                joinColumns = @JoinColumn(name = "user_id"),
                inverseJoinColumns = @JoinColumn(name = "title_id"))
    public Set<Title> getTitles() {
        return titles;
    }
    public void setTitles(Set<Title> titles) {
        this.titles = titles;
    }

}

タイトルエンティティ

public class Title {

    Long id;
    String description;
    Set<User> users = new HashSet<User>();


    @Id
    @GeneratedValue
    @Column(name = "id")    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "description")
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    /*============ Approach1 & Approach2 & Approach3 ============*/
    @ManyToMany
    @JoinTable( name = "tb_title_user",
                joinColumns = @JoinColumn(name = "title_id"),
                inverseJoinColumns = @JoinColumn(name = "user_id"))
    public Set<User> getUsers() {
        return users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
}

単体テスト

public class UserTest {

    @Autowired
    private SessionFactory sessionFactory;


    @Test
    @Rollback(false)
    @Transactional
    public void saveUser(){
        Session session = sessionFactory.getCurrentSession();
        String now = new Date().toString();

        Title title = new Title();
        title.setDescription("TitleDescription: " + now);
        session.save(title);

        User user = new User();
        user.setName("UserName: " + now);
        user.getTitles().add(title);

        session.saveOrUpdate(user);
    }

}

上記のコードを見ると、3つの異なるアプローチがわかります。以下に、データがデータベーステーブルに正しく格納されているかどうかを説明します。

             Title      User     JoinTable
Approach1    Yes        Yes      No
Approach2    Yes        Yes      Yes
Approach3    Yes        Yes      Yes

それぞれのアプローチに関する私の考えは次のとおりです。

アプローチ1

Hibernateのドキュメント(http://docs.jboss.org/hibernate/core/4.1/manual/en-US/html/ch07.html#d5e5537)によると、Approach1に従う必要があります。特に、ドキュメントには次のことが明示的に記載されているためです。

「前に見たように、反対側は物理マッピングを記述する必要はありません(してはいけません)。所有者側のプロパティ名を含む単純なmappedBy引数が2つをバインドします。」</ p>

正しく理解していれば、Userエンティティに@JoinTableを追加する必要はありません(してはいけません)。

アプローチ2

動作しますが、@ JoinTable定義を無視し、次のような独自のテーブルを作成しますtb_user_tb_title。魚臭い匂いがします。

アプローチ3

動作しますが、ドキュメントには使用しないように記載されています。したがって、エンタープライズ製品でこのアプローチを使用したことを後悔しているように思われます。

4

1 に答える 1

4

唯一の正しい方法は最初の方法です:

@ManyToMany(mappedBy = "users")
public Set<Title> getTitles() {
    return titles;
}

...

@ManyToMany
@JoinTable(name = "tb_title_user",
           joinColumns = @JoinColumn(name = "title_id"),
           inverseJoinColumns = @JoinColumn(name = "user_id"))
public Set<User> getUsers() {
    return users;
}

逆側は、mappedBy属性を使用して次のように言います。「私は逆側です。usersターゲットエンティティの属性を参照して、この関連付けがどのようにマッピングされているかを確認してください。」

あなたが間違っているのは、テストの逆側だけを変更することです。JPA / Hibernateは、関連付けが存在するかどうかを知るために所有者側のみを考慮します。だからする代わりに

user.getTitles().add(title);

やったほうがいい

title.getUsers().add(user);

またはさらに良いことに、オブジェクトグラフが一貫していることを確認するために、両方を実行します。

このトレッドが同様の問題のリファレンスになることを本当に望んでいますが、私はすでにこの質問に何億回も答えており、ドキュメントで明確に説明されていますが、何度も何度も答えているので、それは疑わしいです:

アソシエーションが双方向の場合、一方の側が所有者であり、もう一方の側が逆の端である必要があります(つまり、アソシエーションテーブルの関係値を更新するときに無視されます)。

[双方向の多対名の関連付けの両側に適切な注釈を付けた例に従います]

于 2013-03-15T20:04:40.140 に答える