Hibernate(4.1.2)和Spring(3.1.2) - ManyToMany关系不会将记录存储在JoinTable中 [英] Hibernate (4.1.2) and Spring (3.1.2) – ManyToMany relationship does not store records in JoinTable

查看:73
本文介绍了Hibernate(4.1.2)和Spring(3.1.2) - ManyToMany关系不会将记录存储在JoinTable中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到问题,需要您的帮助来解决此问题。希望这个步骤可能成为类似问题的参考......

在我最小化的商业模式中,有用户和标题。标题应该首先创建,并可以分配给许多用户,用户可以共享相同的标题。因此,我创建了两个名为User和Title的实体,并具有@ManyToMany关系,并决定Title应拥有此关系。另外,我有一个UnitTest来运行这个例子。



用户实体

  public class User {

Long id;
字符串名称;
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(名称= USER_ID),
inverseJoinColumns = @JoinColumn(名称= title_id的))
公共组<标题> getTitles(){
返回标题;
}
public void setTitles(Set< Title> titles){
this.titles = titles;
}

}

标题实体 b
$ b

  public class Title {

Long id;
字符串描述;
设置<用户> 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&方法2& Approach3 ============ * /
@ManyToMany
@JoinTable(NAME = tb_title_user,
joinColumns = @JoinColumn(NAME = 的title_id),
inverseJoinColumns = @JoinColumn(name =user_id))
public Set< User> getUsers(){
返回用户;
}
public void setUsers(Set< User> users){
this.users = users;
}
}

UnitTest

  public class UserTest {

@Autowired
private SessionFactory sessionFactory;


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

标题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);
}

}

如果您查看上面的代码,你会看到三种不同的方法。下面描述数据是否正确存储在数据库表中:

 标题用户JoinTable 
方法1是是否
方法2是是是
方法3是是是

每种方法:

Approach1

根据Hibernate文档( http://docs.jboss.org/hibernate/core /4.1/manual/en-US/html/ch07.html#d5e5537 )我应该遵循Approach1。特别是,因为文档明确提到:


如前所述,另一方不必(不得)描述
物理映射:一个简单的mappedBy参数,其中包含所有者
的属性名称将两者绑定。


如果我正确理解,我不必在用户实体中添加@JoinTable。


$ b 方法2



它可以工作,但它会忽略我的@JoinTable定义并创建自己的表,名为: tb_user_tb_title 。它的味道很腥。

Approach3

说不要使用它。所以,在我看来,我可能会后悔在企业产品中使用这种方法。 解决方案

唯一正确的方法是先一:

  @ManyToMany(mappedBy =users)
public Set< Title> getTitles(){
返回标题;
}

...

@ManyToMany
@JoinTable(NAME = tb_title_user,
joinColumns = @JoinColumn(NAME = title_id),
inverseJoinColumns = @JoinColumn(name =user_id))
public Set< User> getUsers(){
返回用户;

$ / code>

反面使用 mappedBy 属性说:我是反面,去看目标实体中的用户属性,看看这个关联是如何映射的。



你做错了什么,只是你在测试中修改了反面。 JPA / Hibernate只考虑所有者方知道是否存在关联。因此,而不是做
$ b

  user.getTitles()。add(title); 

您应该这样做

$ pre> title.getUsers()添加(用户);

甚至更好,确保对象图是一致的。



我真的希望这个问题能够成为类似问题的参考,但我对此表示怀疑,因为我已经回答了这个问题了数十亿次,并且它一再出现,尽管它很清楚在文档中解释:

lockquote

如果关联是双向的,则一方必须是所有者,一方必须是逆向结束(即在更新关联表中的关系值时它将被忽略):

[以下示例显示了双向多对多表中适当的注释, namy association]



I have a problem and need your help to overcome this issue. Hopefully, this tread may become a reference for similar issues…

In my minimized business model there are Users and Titles. Titles should be created first and can be assigned to many Users, and Users may share the same Titles. Therefore I have created two entities called User and Title with a @ManyToMany relationship and decided that Title should own this relationship. Additionally, I have a UnitTest to run this example.

User Entity

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;
    }

}

Title Entity

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;
    }
}

UnitTest

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);
    }

}

If you look at the code above, you are going to see three different approaches. Below, is described if the data is stored correctly in the database tables:

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

Here are my thoughts regarding each approach:

Approach1

According with Hibernate documentation ( http://docs.jboss.org/hibernate/core/4.1/manual/en-US/html/ch07.html#d5e5537 ) I should follow Approach1. Specially, because the documentation explicitly mentions:

"As seen previously, the other side don't have to (must not) describe the physical mapping: a simple mappedBy argument containing the owner side property name bind the two."

If I understood right, I don’t have to (must not) add a @JoinTable in the User entity.

Approach2

It works, but it ignores my @JoinTable definition and creates its own table called: tb_user_tb_title. It smells fishy to me.

Approach3

It works, but the documentation says to do not use it. So, it seems to me that I may regret using this approach in an enterprise product.

解决方案

The only correct way is the first one:

@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;
}

The inverse side uses the mappedBy attribute to say: "I'm the inverse side. Go see the users attribute in the target entity to see how this association is mapped."

What you're doing wrong is that you only modify the inverse side in your test. JPA/Hibernate only considers the owner side to know if an association exists. So instead of doing

user.getTitles().add(title);

you should do

title.getUsers().add(user);

or even better, do both, to make sure the object graph is coherent.

I really hope that this tread becomes a reference for similar issues, but I doubt it, because I have already answered this question a gazillion times, and it keeps coming again and again, although it's clearly explained in the documentation:

If the association is bidirectional, one side has to be the owner and one side has to be the inverse end (ie. it will be ignored when updating the relationship values in the association table):

[ follows an example with the appropriate annotations on each side of a bidirectional many-to-namy association ]

这篇关于Hibernate(4.1.2)和Spring(3.1.2) - ManyToMany关系不会将记录存储在JoinTable中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆