@ManyToMany 保存关系在一个方向上只能使用一次
Posted
技术标签:
【中文标题】@ManyToMany 保存关系在一个方向上只能使用一次【英文标题】:@ManyToMany saving relations is available only one time in one direction 【发布时间】:2020-04-16 08:12:30 【问题描述】:我将尝试在我的 SpringBoot 应用程序中创建 @ManyToMany 关系。 我使用 JPARespository,我创建了 2 个模型:
用户
@Entity(name = "User")
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToMany//(cascade = CascadeType.MERGE, CascadeType.PERSIST)
@LazyCollection(value = LazyCollectionOption.FALSE)
@JoinTable(
name = "users_groups",
joinColumns = @JoinColumn(name = "users_id"),
inverseJoinColumns = @JoinColumn(name = "groups_id")
)
private Set<UGroup> groups;
public User()
this.groups = new HashSet<>();
public void addGroup(UGroup uGroup)
this.groups.add(uGroup);
uGroup.users.add(this);
public void removeGroup(UGroup uGroup)
this.groups.remove(uGroup);
uGroup.users.remove(this);
UGroups
@Data
@Entity(name = "UGroup")
@Table(name = "groups")
public class UGroup
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToMany(mappedBy = "groups", cascade = CascadeType.MERGE, CascadeType.PERSIST)
@LazyCollection(value = LazyCollectionOption.FALSE)
public Set<User> users;
public UGroup()
this.users = new HashSet<>();
public void addUser(User user)
this.users.add(user);
user.getGroups().add(this);
public void removeUser(User user)
this.users.remove(user);
user.getGroups().remove(this);
我通过 DataConfiguration 类加载启动数据:
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent)
User user = new User();
user.setName("Damian");
userRepository.save(user);
user = new User();
user.setName("Marta");
userRepository.save(user);
user = new User();
user.setName("Natalia");
userRepository.save(user);
UGroup uGroup = new UGroup();
uGroup.setName("Mieszkanie");
uGroup = uGroupRepository.save(uGroup);
user = userRepository.findById(1).get();
user.addGroup(uGroup);
user = userRepository.save(user);
// unable to execute
/*
user = userRepository.findById(2).get();
user.addGroup(uGroup);
user = userRepository.save(user);
*/
// unable to execute 2
/*
uGroup = uGroupRepository.findById(4).get();
uGroup.addUser(userRepository.findById(3).get());
uGroup = uGroupRepository.save(uGroup);
*/
当我只为 1 个用户执行插入组时,一切都很好。
虽然当我尝试为 1 和 2 个用户执行插入组或为组插入 3 个用户时,它会导致 java.lang.***Error: null
异常。
我不知道哪里出错了。谁能帮助我并解释我应该在哪里以及为什么要更改某些内容? 提前致谢。
【问题讨论】:
您需要提及连接表和列以使您的 manyTomany 工作 如果我知道正确@JoinTable 是没有必要的,但我尝试使用它。仍然无法正常工作,同样的异常。 通过堆栈跟踪发布您遇到的错误/异常,以便更容易解释/调试问题。 【参考方案1】:通过Join Table,可以映射ManyToMany双向关系。这些是修改后的实体类
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity(name = "User")
@Table(name = "users")
public class User
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Integer getId()
return id;
public String getName()
return name;
public Set<UGroup> getGroups()
return groups;
public void setGroups(Set<UGroup> groups)
this.groups = groups;
public void setName(String name)
this.name = name;
@ManyToMany(mappedBy = "users",cascade = CascadeType.ALL)
@LazyCollection(value = LazyCollectionOption.FALSE)
private Set<UGroup> groups=new HashSet<UGroup>();
public User()
public void addGroup(UGroup uGroup)
this.groups.add(uGroup);
uGroup.users.add(this);
public void removeGroup(UGroup uGroup)
this.groups.remove(uGroup);
uGroup.users.remove(this);
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity(name = "UGroup")
@Table(name = "groups")
public class UGroup
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "USER_GROUP_MAP" ,joinColumns = @JoinColumn(name="GROUP_ID",referencedColumnName = "ID")
,inverseJoinColumns = @JoinColumn(name="USER_ID",referencedColumnName = "ID"))
@LazyCollection(value = LazyCollectionOption.FALSE)
public Set<User> users=new HashSet<>();
public UGroup()
public void addUser(User user)
this.users.add(user);
user.addGroup(this);
public void removeUser(User user)
this.users.remove(user);
user.removeGroup(this);
public Integer getId()
return id;
public String getName()
return name;
public void setName(String name)
this.name = name;
public Set<User> getUsers()
return users;
public void setUsers(Set<User> users)
this.users = users;
对于多对多关系,连接表是必要的。
SELECT * FROM USER_GROUP_MAP;
GROUP_ID USER_ID
4 1
4 2
4 3
这是您发布的代码的结果。您应该覆盖两个实体类中的 hashcode 和 equals 方法,以避免表中的数据重复。
用于测试上述关系映射的代码。
@Override
public void onApplicationEvent(ContextRefreshedEvent applicationEvent)
User user = new User();
user.setName("Damian");
userRepository.save(user);
user = new User();
user.setName("Marta");
userRepository.save(user);
user = new User();
user.setName("Natalia");
userRepository.save(user);
UGroup uGroup = new UGroup();
uGroup.setName("Mieszkanie");
uGroup = uGroupRepository.save(uGroup);
user = userRepository.findById(1).get();
user.addGroup(uGroup);
user = userRepository.save(user);
// unable to execute
user = userRepository.findById(2).get();
user.addGroup(uGroupRepository.findById(4).get());
user = userRepository.save(user);
// unable to execute 2
uGroup = uGroupRepository.findById(4).get();
uGroup.addUser(userRepository.findById(3).get());
uGroup = uGroupRepository.save(uGroup);
【讨论】:
我执行了你的代码。它对我不起作用... :-( 我重写了 equals 和 hashCode 方法,运行后我收到:Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_C ON PUBLIC.USER_GROUP_MAP(GROUP_ID, USER_ID) VALUES 1"; SQL statement: insert into user_group_map (group_id, user_id) values (?, ?) [23505-199]
似乎您正在关联 USER_GROUP_MAP 表中的重复条目。Hibernate 正在尝试为相同的关联插入重复的行。还要从等号代码中排除 Id,因为在这种情况下 id 是代理键。
是的,我知道,我在评论之前搜索了这个错误,但是每次运行程序都会创建 H2 数据库,所以数据库肯定是空的。具有数据加载的类运行一次。我不知道我应该做什么。
由于onApplicationEvent尝试了spring的生命周期,数据可能会被插入两次。尝试调试此方法以检查它是否被调用了两次。
Hurra 它有效:-D 非常感谢。另外我观察到使用lookbook有时会导致***Error,所以我必须忘记使用它:-(以上是关于@ManyToMany 保存关系在一个方向上只能使用一次的主要内容,如果未能解决你的问题,请参考以下文章
在 typeORM 中的 @ManyToMany 中保存关系会覆盖先前的条目