插入时出现@OneToMany SQLIntegrityConstraintViolationException错误(Hibernate)

时间:2014-03-25 16:44:39

标签: java spring hibernate spring-mvc

我在使用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;。任何想法??

1 个答案:

答案 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()。