Reputation: 3927
I have a many-to-many relation in my project and although I'm able to write in my two Entities table, the relational table does not get anything written.
Here's how I'm declaring this using JPA annotations:
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
}
And here is the service layer to insert into database:
@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);
...
}
In this case, please consider that I already have an entry with id "1" for Professor.
As I said, it does write on Aluno and Professor table but does NOT write anything into ALUNO_PROFESSOR table.
I've already taken a look at these three kind of similiar questions but none of them could help me:
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
EDIT - Adding more code snippets
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);
}
}
Upvotes: 3
Views: 22012
Reputation: 181
Some times the problem is in the way that you insert the values. I explain with an example.
User user = userFacade.find(1);
Post post = new Post("PRUEBA");
user.addPostCollection(post);
post.addUserCollection(user);
postFacade.create(post);
You have to add the post in postCollection and the user in userCollection. You have two add the correspond entity in the collections of the two entities.
Class USER
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;
Also, it is important to instance the list, for example userCollection = new ArrayList(). If you do not, the value won´t insert.
Upvotes: 0
Reputation: 513
...
Normally, Hibernate holds the persistable state in memory. The process of synchronizing this state to the underlying DB is called flushing.
When we use the save() method, the data associated with the save operation will not be flushed to the DB unless and until an explicit call to flush() or commit() method is made.
If we use JPA implementations like Hibernate, then that specific implementation will be managing the flush and commit operations.
One thing we have to keep in mind here is that, if we decide to flush the data by ourselves without committing it, then the changes won't be visible to the outside transaction unless a commit call is made in this transaction or the isolation level of the outside transaction is READ_UNCOMMITTED.
...
From Difference Between save() and saveAndFlush() in Spring Data JPA by baeldung: https://www.baeldung.com/spring-data-jpa-save-saveandflush
employeeRepository.saveAndFlush(new Employee(2L, "Alice"));
or
employeeRepository.save(new Employee(2L, "Alice"));
employeeRepository.flush();
Upvotes: 1
Reputation: 5683
Its not necessary to set many-to-many relationship on both entities.
Just remove session.setFlushMode(FlushMode.MANUAL);
By default HibernateTemplate inside of Spring set FlushMode.MANUAL
this is source code from HibernateTemplate
.
if (session == null) {
session = this.sessionFactory.openSession();
session.setFlushMode(FlushMode.MANUAL);
isNew = true;
}
Upvotes: 0
Reputation: 41
I have the same issue. I swapped where the full mapping declare to the class that we will use save() function on. In your case:
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;
}
and It worked fine.
Upvotes: 4
Reputation: 20135
Try this:
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;
}
This will ensure that the metadata for the many-to-many relationship is available on both the entities and that operations on either side of the relationship are cascaded to the other side.
I also suggest replacing FetchType.EAGER
with FetchType.LAZY
for better performance because this has the potential of loading a very large dataset.
Upvotes: 15