I am having trouble inserting records with a @OneToMany relationship using Hibernate and Spring MVC. I can successfully insert records without adding anything to the @OneToMany collection. However, upon adding a collection record, it fails stating that there is a SQLIntegrityConstraintViolationException.
My current code for the mapping (annotation-style) is as follows:
Contact.java
package mil.navy.navsupbsc.entity;
import java.util.Collection;
import java.util.LinkedHashSet;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@Entity
@Table(name = "CONTACT2")
public class Contact extends Auditable {
public Contact() {
}
// Create with mandatory fields
public Contact(long id, Salutation salutation, String firstName,
String middleInitial, String lastName,
MilitaryCivilianInformation milCivInfo) {
this.setContactId(id);
this.setSalutation(salutation);
this.setFirstName(firstName);
this.setMiddleInitial(middleInitial);
this.setLastName(lastName);
this.setMilitaryCivilianInformation(milCivInfo);
}
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@SequenceGenerator(name = "CONTACT_SEQ")
@Column(name = "CONTACT_ID")
private Long contactId;
@Fetch(FetchMode.SUBSELECT)
@OneToMany(cascade = { CascadeType.ALL, CascadeType.REMOVE }, mappedBy = "contact", orphanRemoval = true)
private Collection<Email> emails = new LinkedHashSet<Email>();
/**
* @return the emails
*/
public Collection<Email> getEmails() {
for (Email email : emails) {
email.getEmailType();
}
return emails;
}
/**
* @param emails
* the emails to set
*/
public void setEmails(Collection<Email> emails) {
this.emails.clear();
for (Email email : emails) {
this.addEmail(email);
}
}
public void addEmail(Email email) {
email.setContact(this);
this.getEmails().add(email);
}
[...more Getters / Setters and fields]
}
Email.java
package mil.navy.navsupbsc.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.codehaus.jackson.annotate.JsonBackReference;
/**
* Implements Auditing Properties
*/
@Entity
@Table(name = "EMAIL")
public class Email extends Auditable {
private static final long serialVersionUID = -4833322552325183301L;
@Id
@GeneratedValue
@SequenceGenerator(name = "EMAIL_SEQ")
@Column(name = "EMAIL_ID")
private long emailId;
@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONTACT_FK")
private Contact contact;
[More fields]
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
public long getEmailId() {
return emailId;
}
public void setEmailId(long emailId) {
this.emailId = emailId;
}
[more getters / setters]
}
ContactDAOImpl (I've tried many variations of this with no success)
public void saveContact(Contact contact) {
Session session = sessionFactory.getCurrentSession();
Collection<Email> emailCollection = new LinkedHashSet<Email>();
emailCollection = contact.getEmails();
Contact contactToSave;
long contactId;
if (contact.getContactId() == 0 || contact.getContactId() == null) {
contactToSave = new Contact((long) 0, contact.getSalutation(),
contact.getFirstName(), contact.getMiddleInitial(),
contact.getLastName(),
contact.getMilitaryCivilianInformation());
session.save(contactToSave);
session.flush();
for (Email email : emailCollection) {
// email.setContact(contactToSave);
contactToSave.addEmail(email);
}
session.saveOrUpdate(contactToSave);
session.flush();
session.clear();
}
Any help with this is much appreciated. I had a previous version of this that updated records correctly, but can't seem to work out the Save new records. I also originally used the contact that I passed in from the web service, but I attempted to create a new record in the DAO to eliminate potential problems in the latest variation of my code.
Also, I know that there are many similar questions, but I have tried many of the answers with no success (hence the new question).
Thank you for your help!
UPDATE
I checked to see what ID the data layer returns after the initial save and verified (unsuccessfully) that the same ID was saved in the database. The returned ID is different than the saved ID. For example, the latest save showed the Contact ID as '1129' with the returned contact after the initial save. I did a retrieve from the database with contact ID '1129' - and it successfully returned the contact. After closing the transaction, I viewed the data directly in the database. The database showed '193' as the Contact ID instead of '1129'. Any ideas??