【问题标题】:Jpa ManyToMany relationships doesn't workJpa 多对多关系不起作用
【发布时间】:2019-04-23 16:21:27
【问题描述】:

我有 SpringBoot 2.1.3 + MySql 5.7 数据库。我正在尝试在 2 个实体之间建立多对多关系:

@Entity
@Data
public class User {
    private String name;
    @ManyToMany(cascade = CascadeType.ALL)
    private List<Hobby> hobbies;
}

@Entity
@Data
public class Hobby {
    private String description;
    @ManyToMany(mappedBy = "hobbies")
    private List<User> users;
}

现在如果我做一个测试:

User user = new User();
user.setName("James");
user.setHobbies(new ArrayList<>());

Hobby hobby = new Hobby();
hobby.setDescription("Golf");
hobby.setUsers(new ArrayList<>());

user.getHobbies.add(hobby);
hobby.getUsers.add(user);

userRepository.save(user);

所有三个表(用户表、爱好表和 jpa 创建的映射表)都被持久化如下:

USER              USER_HOBBY               HOBBY
id, name          iduser, idhobby          id, description
1   James         1        1               1   Golf

但如果我现在打电话

List<User> us = userRepository.findAll();

我们我没有任何爱好实体。它说:

com.sun.jdi.InvocationException occurred invoking method.

我的 application.properties 与 db 配置:

# Connection url for the database "test"
spring.datasource.url = jdbc:mysql://localhost:3306/test?useSSL=false

# ===============================
# = JPA / HIBERNATE
# ===============================

spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true

我已经按照谷歌找到的所有示例尝试了所有方法。 怎么了??

谢谢

【问题讨论】:

  • 嗨,我有一个小问题,是否允许重复的爱好,假设我们只有用户应该选择的预定义爱好,如何实现呢?

标签: mysql spring-boot jpa


【解决方案1】:

我认为您在致电userRepository.findAll() 之前不会保存爱好实体。

如果创建实体之间的关系,则需要在保存和搜索全局实体之前保存所有实体依赖项。

如果您在依赖字段中保存带有 NULL 的实体,它们不会抛出异常。在您的情况下,您保存空列表,但休眠无法保存,因为他检查 FK 并没有找到这个爱好。

您可以尝试使用 NULL 或存在于数据库爱好中来保存用户。像这样:

List<Hobby> hobbies = hobbyRepository.findAll();

user.getHobbies().addAll(hobbies); // null pointer exception
userRepository.save(user);

userRepository.findAll();

我不明白为什么您的存储库允许您保存。我在 JpaRepository 上使用 postgres 和接口扩展,如果我用空的爱好列表保存用户,它们会抛出异常。


我试过了:

Hobby h = new Hobby();
h.setDesc("Golf");
hobbyRepository.save(h);

List<Hobby> hobbies = hobbyRepository.findAll();

Persona p = new Persona();
p.setNome("Giacomo");
p.setHobbies(new ArrayList<>());
p.getHobbies().addAll(hobbies);
personaRepository.save(p);

List<Persona> persone = personaRepository.findAll();
List<Hobby> hobby = hobbyRepository.findAll();

不起作用..你能做一个类似于这个的工作示例吗?我会很感激,因为我不明白错误在哪里.. 附:如果我说:

@ManyToMany(fetch = FetchType.EAGER)

它有效..但我不想把它!它应该使用默认值..

【讨论】:

  • 感谢您的回复..我会在调用 findAll() 方法之前尝试保存所有内容,但关于您的疑问,您可能读错了..没有什么是空的,我在调用 user.getHobbies.add(hobby);hobby.getUsers.add(user); 以避免 NullPointerException 并在最后保存用户。如果你复制整个代码并尝试测试它不会抛出任何异常..
【解决方案2】:

解决了。这是一个会话问题,有不同的解决方案。

首先是添加fetch注解:

@Entity
@Data
public class User {
  private String name;
  @ManyToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
  private List<Hobby> hobbies;
}

这样每次你找到用户实体时,你都会获取所有相关的爱好。其他解决方案(更好)是保留默认获取值(对于多对多关系延迟)并在您用于检索数据的方法上添加 @Transactional 注释。

@Transactional
public void searchData() {
  User user = new User();
  user.setName("James");
  user.setHobbies(new ArrayList<>());

  Hobby hobby = new Hobby();
  hobby.setDescription("Golf");
  hobby.setUsers(new ArrayList<>());

  user.getHobbies.add(hobby);
  hobby.getUsers.add(user);

  userRepository.save(user);

  List<User> us = userRepository.findAll();
  for (User u : us) {
    System.out.println(u.getHobbies().size()); // print 1
  }
}

希望有帮助..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-11
    • 2018-04-04
    • 2021-02-05
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 2017-07-18
    相关资源
    最近更新 更多