Norbert94
Norbert94

Reputation: 173

JPA ManyToMany -relationship - joinTable not populated

My Join-Table will be not populated, Here are my classes:

@Entity
@Table(name = "RECIPIENT")
public class Recipient implements Serializable {

    @ManyToMany(targetEntity = Email.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "EMAIL_RECIPIENT", joinColumns = {@JoinColumn(name = "RECIPIENT_ID", nullable = false, updatable = false)},
            inverseJoinColumns = {@JoinColumn(name = "EMAIL_ID", nullable = false)})
    @Fetch(FetchMode.SELECT)
 private Set<Email> emails;

}

@Entity
@Table(name = "EMAIL")
public class Email implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "EMAIL_ID")
    private Integer emailId;

    @ManyToMany(targetEntity = Recipient.class, mappedBy = "emails")
    private Set<Recipient> recipients;

}

In my services-class I save the data the following way:

public void saveEmail(EmailDTO emailDTO) {
    //Save to the db
    final Email myEmail = new Email();
    myEmail .copyFrom(emailDTO);
    for (Recipient recipient : myEmail.getRecipients()) {
        recipient.getEmails().add(myEmail );
        recipientRepository.save(recipient);
    }
    recipientRepository.flush();
    emailRepository.save(myEmail );
    emailRepository.flush();
}

Now my join-table looks like this:

 Email-ID       Recipient_ID
 67891          [email protected]

It only does an update..the join table should look like this:

 Email-ID       Recipient_ID
 12343          [email protected]
 54678          [email protected]
 67891          [email protected]

EDIT

I was wrong it doesn't do an update..I saw in the log files that it deletes the inserted row from.before for example if in a join-table there would be a row like this:

Email-ID    : 1234  , 
Recipient_ID:[email protected]

then it just deletes this row and adds the new email id like:

Email-ID    : 5678  Recipient_ID:[email protected]

This is in the logs, first it deletes:

delete from email_recipient where recipient_id=? and email_id=?

Then it inserts:

insert into email_recipient (recipient_id, email_id) values (?, ?)

Upvotes: 2

Views: 2317

Answers (1)

Amer Qarabsa
Amer Qarabsa

Reputation: 6574

This is a bidirectional relation which means each side of the relation should have a reference to the other side, so in addition to your email having a list of recipents, each recipent need to have a list of emails, so I would suggest to initialize the list of emails inside recipent, your Recipient class should look like this

@Entity
@Table(name = "RECIPIENT")
public class Recipient implements Serializable {

@ManyToMany(targetEntity = Email.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "EMAIL_RECIPIENT", joinColumns = {@JoinColumn(name = "RECIPIENT_ID", nullable = false, updatable = false)},
        inverseJoinColumns = {@JoinColumn(name = "EMAIL_ID", nullable = false)})
@Fetch(FetchMode.SELECT)
 private List<Email> emails = new ArrayList<>()
...getter setters
}

now when iterating over the Recipent add email to the list of emails for each recipent

 List<Recipient> recipientList = new ArrayList<Recipient>(email.getRecipients());
email.setRecipients(new ArrayList<Recipient>());
 for (Recipient recipient : recipientList) {
        recipient.getEmails().add(email);
          email.getRecipients().add(email);
         Recipient persistedRecipient = recipientRepository.save(recipient);

         email = persistedRecipient.getEmails().get(persistedRecipient.getEmails().size()-1);//get the managed email
    }

Another approach would be doing the same (adding the email to recipient) and change the cascade to be in the email and saving the email.

@Entity
@Table(name = "RECIPIENT")
public class Recipient implements Serializable {

@ManyToMany(targetEntity = Email.class)
@JoinTable(name = "EMAIL_RECIPIENT", joinColumns = {@JoinColumn(name = "RECIPIENT_ID", nullable = false, updatable = false)},
        inverseJoinColumns = {@JoinColumn(name = "EMAIL_ID", nullable = false)})
@Fetch(FetchMode.SELECT)
private Set<Email> emails = new HashSet<>();

}

@Entity
@Table(name = "EMAIL")
public class Email implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "EMAIL_ID")
private Integer emailId;

@ManyToMany(targetEntity = Recipient.class, mappedBy = "emails"وcascade = CascadeType.ALL)
private Set<Recipient> recipients = new HashSet<>();

}

And in your saveEmail method

public void saveEmail(EmailDTO emailDTO) {
//Save to the db
final Email myEmail = new Email();
myEmail .copyFrom(emailDTO);
for (Recipient recipient : myEmail.getRecipients()) {
    recipient.getEmails().add(myEmail );

}

emailRepository.save(myEmail );

}

Upvotes: 1

Related Questions