JPA 多对多关系未插入生成的 table

JPA many to many relation not inserting into generated table

我的项目中有一个多对多关系,虽然我可以在我的两个实体 table 中写入,但关系 table 没有写入任何内容。

下面是我如何使用 JPA 注释声明它:

Professor.java

@Entity
@Table(name = "Professor")
public class Professor implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "idProfessor", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "ALUNO_PROFESSOR",
            joinColumns = @JoinColumn(name = "idProfessor", referencedColumnName = "idProfessor"),
            inverseJoinColumns = @JoinColumn(name = "idAluno", referencedColumnName = "idAluno"))
    private List<Aluno> alunoList;

    // getters and setters
}

Aluno.java

@Entity
@Table(name = "Aluno")
public class Aluno implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "idAluno", nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToMany(mappedBy = "alunoList", fetch = FetchType.EAGER)
    private List<Professor> professorList;

    // getters and setters
}

这是要插入数据库的服务层:

@Autowired
private AlunoDao alunoDao;

@Autowired
private ProfessorDao professorDao;

@RequestMapping(value = RestUriConstants.SUBMETER, method = RequestMethod.POST)
public @ResponseBody JsonResponse submeter(@RequestBody final Aluno aluno) {

    Professor professor = professorDao.find(1);
    aluno.setProfessorList(Arrays.asList(professor));
    alunoDao.persist(aluno);

    ...
}

在这种情况下,请考虑我已经为教授创建了一个 ID 为“1”的条目。

正如我所说,它确实在 Aluno 和 Professor table 上写入,但不会将任何内容写入 ALUNO_PROFESSOR table。

我已经看过这三种类似的问题,但其中 none 可以帮助我:

Hibernate and Spring: value of many-to-many not inserted into generated table

JPA many-to-many persist to join table

How to persist @ManyToMany relation - duplicate entry or detached entity

编辑 - 添加更多代码片段

JpaAlunoDao.java

@Repository
public class JpaAlunoDao implements AlunoDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void persist(Aluno aluno) {
        em.persist(aluno);
    }
}

JpaExercicioDao.java

@Repository
public class JpaExercicioDao implements ExercicioDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void persist(Exercicio exercicio) {
        em.persist(exercicio);
    }
}

试试这个:

public class Professor {
  @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @JoinTable(name = "ALUNO_PROFESSOR",
        joinColumns = @JoinColumn(name = "idProfessor", referencedColumnName = "idProfessor"),
        inverseJoinColumns = @JoinColumn(name = "idAluno", referencedColumnName = "idAluno"))
  private List<Aluno> alunoList;
}

public class Aluno {
  @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @JoinTable(name = "ALUNO_PROFESSOR",
        joinColumns = @JoinColumn(name = "idAluno", referencedColumnName = "idAluno"),
        inverseJoinColumns = @JoinColumn(name = "idProfessor", referencedColumnName = "idProfessor"))
  private List<Professor> professorList;
}

这将确保多对多关系的元数据在两个实体上都可用,并且关系两侧的操作级联到另一侧。

我还建议将 FetchType.EAGER 替换为 FetchType.LAZY 以获得更好的性能,因为这有可能加载非常大的数据集。

我也有同样的问题。我将完整映射声明的位置交换为我们将在其上使用 save() 函数的 class。 你的情况:

public class Aluno {
  @ManyToMany(fetch = FetchType.EAGER)
  @JoinTable(name = "ALUNO_PROFESSOR",
        joinColumns = @JoinColumn(name = "idAluno"),
        inverseJoinColumns = @JoinColumn(name = "idProfessor")
  private List<Professor> professorList;
}

public class Professor {
  @ManyToMany(fetch = FetchType.EAGER, mappedBy = "professorList",)  
  private List<Aluno> alunoList;
}

而且效果很好。

没有必要在两个实体上设置多对多关系。

只需删除session.setFlushMode(FlushMode.MANUAL);

默认情况下 Spring 内的 HibernateTemplate 设置 FlushMode.MANUAL

这是来自 HibernateTemplate 的源代码。

 if (session == null) {
            session = this.sessionFactory.openSession();
            session.setFlushMode(FlushMode.MANUAL);
            isNew = true;
        }

...

通常,Hibernate 在内存中保存可持久化状态。将这个状态同步到底层DB的过程称为flushing。

当我们使用 save() 方法时,与保存操作相关的数据不会被刷新到 DB,除非并且直到显式调用 flush() 或 commit() 方法.

如果我们使用像 Hibernate 这样的 JPA 实现,那么该特定实现将管理刷新和提交操作。

这里我们要记住的一件事是,如果我们决定自己刷新数据而不提交数据,那么除非在此调用提交,否则外部事务将看不到更改事务或外部事务的隔离级别是READ_UNCOMMITTED。

...

来自 baeldung 的 Spring Data JPA 中 save() 和 saveAndFlush() 的区别: https://www.baeldung.com/spring-data-jpa-save-saveandflush

employeeRepository.saveAndFlush(new Employee(2L, "Alice"));

  employeeRepository.save(new Employee(2L, "Alice"));
  employeeRepository.flush();

有时问题出在您插入值的方式上。我举例说明。

User user = userFacade.find(1);      
Post post = new Post("PRUEBA");
user.addPostCollection(post);
post.addUserCollection(user);
postFacade.create(post);

您必须在 postCollection 中添加 post,在 userCollection 中添加用户。你有两个在两个实体的集合中添加对应的实体。

Class 用户

  public void addPostCollection(Post post) {
    if(postCollection == null){
        postCollection = new ArrayList<Post>();
    }
    postCollection.add(post);
}

@ManyToMany(mappedBy = "userCollection")
private Collection<Post> postCollection;

Class Post

    public void addUserCollection(User user){
        if(userCollection == null){
            userCollection = new ArrayList<User>();
        }
        userCollection.add(user);
    }

 @JoinTable(name = "USER_POST_R", joinColumns = {
 @JoinColumn(name = "POSTID", referencedColumnName = "ID")}, inverseJoinColumns = {
 @JoinColumn(name = "USERID", referencedColumnName = "ID")})
    @ManyToMany
    private Collection<User> userCollection;

此外,实例化列表也很重要,例如 userCollection = new ArrayList()。如果不这样做,则不会插入该值。