我在使用Hibernate和Spring MVC插入具有@OneToMany关系的记录时遇到问题。我可以成功插入记录而无需向@OneToMany集合添加任何内容。但是,在添加集合记录时,它无法声明存在SQLIntegrityConstraintViolationException。
我目前的映射代码(注释样式)如下:
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 (我已尝试过多种变体而没有成功)
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();
}
非常感谢任何帮助。我之前的版本正确更新了记录,但似乎无法解决保存新记录的问题。我最初也使用了从Web服务传入的联系人,但我尝试在DAO中创建一个新记录,以消除我的代码的最新变体中的潜在问题。
此外,我知道有很多类似的问题,但我已经尝试了许多答案但没有成功(因此是新问题)。
感谢您的帮助!
更新
我检查了初始保存后数据层返回的ID,并验证(未成功)数据库中保存了相同的ID。返回的ID与保存的ID不同。例如,最新的保存显示联系人ID为&#39; 1129&#39;初始保存后返回的联系人。我从数据库中检索了联系人ID&#39; 1129&#39; - 它成功地返回了联系人。关闭事务后,我直接在数据库中查看了数据。数据库显示&#193; 193&#39;作为联系人ID而不是&#39; 1129&#39;。任何想法??
答案 0 :(得分:0)
我想出了我遇到的问题。
在创建Hibernate实体定义之前,我直接在数据库中创建了一个序列和触发器。我还在JAVA hibernate代码中的实体定义中指定了相同的序列。 但是,我生成序列的语法不完整。
由于生成序列的语法不完整,JAVA代码使用的是默认的HIBERNATE_SEQUENCE生成器,而不是我创建的序列。 Hibernate从HIBERNATE_SEQUENCE返回序列值(在数据库插入之前创建ID)。但是,在将值插入数据库之前,Oracle会运行我的自定义序列并将Contact ID分配给新生成的值。
因此,当我尝试向集合添加值时,Insert语句尝试使用Hibernate生成的序列值作为外键,而不是数据库生成的序列值。
为了确保Hibernate代码和数据库同步,我从数据库中删除了ContactID触发器。根据StackOverflow(Hibernate and Oracle Sequence)中的另一个问题,我将Contact.java ContactID声明的JAVA Hibernate代码更新为:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CONTACT_SEQ")
@SequenceGenerator(name = "CONTACT_SEQ", sequenceName = "contact_seq", allocationSize = 1)
@Column(name = "CONTACT_ID")
private Long contactId;
谢天谢地,这解决了这个问题。 JAVA Hibernate代码现在通过我指定的序列创建ID。然后数据库成功将这些值插入数据库!
我还能将我的保存简化为:
public void saveContact(Contact contact) {
Session session = sessionFactory.getCurrentSession();
if (contact.getContactId() == 0 || contact.getContactId() == null) {
session.save(contact);
session.flush();
}
}
我确定我需要再次更改它,但要考虑更新联系人 - 可能使用saveOrUpdate()而不是save()。