【问题标题】:@OneToMany SQLIntegrityConstraintViolationException error upon insert (Hibernate)@OneToMany SQLIntegrityConstraintViolationException 插入时出错(休眠)
【发布时间】:2014-03-25 16:44:38
【问题描述】:

我在使用 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]

}

电子邮件.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 为“1129”,初始保存后返回的联系人。我从数据库中检索了联系人 ID '1129' - 它成功返回了联系人。关闭事务后,直接查看数据库中的数据。数据库将“193”显示为联系人 ID,而不是“1129”。有什么想法吗??

【问题讨论】:

  • 你也可以发布堆栈跟踪吗?
  • @Nivas - 我发现了问题......原来这是因为直接在数据库中使用触发器,而不是在插入之前使用通过 Hibernate 生成的值。我也有不正确的语法来指示 Hibernate 使用我的自定义序列生成器而不是默认的 Hibernate 序列生成器。由于它现在可以工作,我没有堆栈跟踪。感谢您查看问题!如果您对我发布的解决方案有任何进一步的建议,请随时发布 - 我还是 Hibernate 和 JAVA 的新手 - 所以我非常感谢我收到的帮助!

标签: java spring hibernate spring-mvc


【解决方案1】:

我发现了我遇到的问题。

在创建 Hibernate 实体定义之前,我直接在数据库中创建了一个序列和触发器。我还在 JAVA hibernate 代码中的实体定义中指定了相同的序列。 但是,我生成序列的语法不完整

由于生成序列的语法不完整,JAVA 代码使用默认的 HIBERNATE_SEQUENCE 生成器,而不是我创建的序列。 Hibernate 从 HIBERNATE_SEQUENCE 返回序列值(在数据库插入之前创建 ID)。但是,在将值插入数据库之前,Oracle 运行了我的自定义序列并将联系人 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()。

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 2015-07-07
    相关资源
    最近更新 更多