Hibernate映射一对多问题

时间:2011-01-16 01:11:08

标签: java hibernate one-to-many

我对Hibernate不太熟悉,我正在尝试创建一对多映射。

以下是相关表格: alt text

这是我的映射文件:

<hibernate-mapping package="com.xorty.mailclient.server.domain">
  <class name="Attachment" table="Attachment">
    <id name="id">
        <column name="idAttachment"></column>
    </id>
    <property name="filename">
        <column name="name"></column>
    </property>
    <property name="blob">
        <column name="file"></column>
        <type name="blob"></type>
    </property>
    <property name="mailId">
        <column name="mail_idmail"></column>
    </property>
  </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="com.xorty.mailclient.server.domain.Mail" table="mail">
        <id name="id" type="integer" column="idmail"></id>
        <property name="content">
            <column name="body"></column>
        </property>
        <property name="ownerAddress">
            <column name="account_address"></column>
        </property>
        <property name="title">
            <column name="head"></column>
        </property>
        <set name="receivers" table="mail_has_contact" cascade="all">
            <key column="mail_idmail"></key>
            <many-to-many column="contact_address" class="com.xorty.mailclient.client.domain.Contact"></many-to-many>
        </set>
        <bag name="attachments" cascade="save-update, delete" inverse="true">
        <key column="mail_idmail" not-null="true"/>
        <one-to-many class="com.xorty.mailclient.server.domain.Attachment"/>
    </bag>
    </class>
</hibernate-mapping>

简单来说,一封邮件附件更多。 当我尝试在没有附件的邮件上进行CRUD时,每个工作都很好。当我向邮件添加一些附件时,我无法执行任何CRUD操作。

我最终得到以下追踪:

org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at domain.DatabaseTest.testPersistMailWithAttachment(DatabaseTest.java:355)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at junit.framework.TestCase.runTest(TestCase.java:168)
    at junit.framework.TestCase.runBare(TestCase.java:134)
    at junit.framework.TestResult$1.protect(TestResult.java:110)
    at junit.framework.TestResult.runProtected(TestResult.java:128)
    at junit.framework.TestResult.run(TestResult.java:113)
    at junit.framework.TestCase.run(TestCase.java:124)
    at junit.framework.TestSuite.runTest(TestSuite.java:232)
    at junit.framework.TestSuite.run(TestSuite.java:227)
    at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (`maildb`.`attachment`, CONSTRAINT `fk_Attachment_mail1` FOREIGN KEY (`mail_idmail`) REFERENCES `mail` (`idmail`) ON DELETE NO ACTION ON UPDATE NO ACTION)
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1666)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1082)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    ... 27 more

谢谢

编辑:关于hvgotcodes提案:

package com.xorty.mailclient.server.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.xorty.mailclient.client.domain.Account;
import com.xorty.mailclient.client.domain.AttachmentDTO;
import com.xorty.mailclient.client.domain.Contact;
import com.xorty.mailclient.client.domain.MailDTO;

/**
 * Heavy weight Hibernate Mail
 * @author MisoV
 * @version 0.1
 */
public class Mail implements Serializable {

    private List<Attachment> attachments = new ArrayList<Attachment>();

    private String content;
    private int id;
    private boolean isNew;
    private Account owner;
    private String ownerAddress;
    private Set<Contact> receivers = new HashSet<Contact>();
    private String sender;
    private String title;
    /**
     * Hibernate purposes
     */
    public Mail() { // $codepro.audit.disable
    }
    /**
     * Unwraps light DTO object to heavy Hibernate object.
     * @param dto Corresponding DTO class.
     */
    public Mail(final MailDTO dto) {
        for (final AttachmentDTO attachmentDTO : dto.getAttachments()) {
            attachments.add(new Attachment(attachmentDTO));
        }
        content = dto.getContent();
        id = dto.getId();
        isNew = dto.isNew();
        owner = dto.getOwner();
        ownerAddress = dto.getOwnerAddress();
        receivers = dto.getReceivers();
        sender = dto.getSender();
        title = dto.getTitle();
    }

    /**
     * Inserts new attachment
     * @param attachment
     */
    public void addAttachment(final Attachment attachment) {
        attachments.add(attachment);
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Mail)) {
            return false;
        }
        final Mail other = (Mail) obj;
        if (attachments == null) {
            if (other.attachments != null) {
                return false;
            }
        } else if (!attachments.equals(other.attachments)) {
            return false;
        }
        if (content == null) {
            if (other.content != null) {
                return false;
            }
        } else if (!content.equals(other.content)) {
            return false;
        }
        if (id != other.id) {
            return false;
        }
        if (isNew != other.isNew) {
            return false;
        }
        if (owner == null) {
            if (other.owner != null) {
                return false;
            }
        } else if (!owner.equals(other.owner)) {
            return false;
        }
        if (ownerAddress == null) {
            if (other.ownerAddress != null) {
                return false;
            }
        } else if (!ownerAddress.equals(other.ownerAddress)) {
            return false;
        }
        if (receivers == null) {
            if (other.receivers != null) {
                return false;
            }
        } else if (!receivers.equals(other.receivers)) {
            return false;
        }
        if (sender == null) {
            if (other.sender != null) {
                return false;
            }
        } else if (!sender.equals(other.sender)) {
            return false;
        }
        if (title == null) {
            if (other.title != null) {
                return false;
            }
        } else if (!title.equals(other.title)) {
            return false;
        }
        return true;
    }

    /**
     * @return the attachments
     */
    public List<Attachment> getAttachments() {
        return attachments;
    }
    /**
     * @return the content
     */
    public String getContent() {
        return content;
    }
    /**
     * @return the id
     */
    public int getId() {
        return id;
    }
    /**
     * @return the owner
     */
    public Account getOwner() {
        return owner;
    }
    /**
     * @return the ownerAddress
     */
    public String getOwnerAddress() {
        return ownerAddress;
    }
    /**
     * @return the receivers
     */
    public Set<Contact> getReceivers() {
        return receivers;
    }
    /**
     * @return the sender
     */
    public String getSender() {
        return sender;
    }
    /**
     * @return the title
     */
    public String getTitle() {
        return title;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((attachments == null) ? 0 : attachments.hashCode());
        result = prime * result + ((content == null) ? 0 : content.hashCode());
        result = prime * result + id;
        result = prime * result + (isNew ? 1231 : 1237);
        result = prime * result + ((owner == null) ? 0 : owner.hashCode());
        result = prime * result
                + ((ownerAddress == null) ? 0 : ownerAddress.hashCode());
        result = prime * result
                + ((receivers == null) ? 0 : receivers.hashCode());
        result = prime * result + ((sender == null) ? 0 : sender.hashCode());
        result = prime * result + ((title == null) ? 0 : title.hashCode());
        return result;
    }
    /**
     * @return the isNew
     */
    public boolean isNew() {
        return isNew;
    }
    /**
     * @param attachments the attachments to set
     */
    public void setAttachments(final List<Attachment> attachments) {
        this.attachments = attachments;
    }
    /**
     * @param content the content to set
     */
    public void setContent(final String content) {
        this.content = content;
    }
    /**
     * @param id the id to set
     */
    public void setId(final int id) {
        this.id = id;
    }
    /**
     * @param isNew the isNew to set
     */
    public void setNew(final boolean isNew) {
        this.isNew = isNew;
    }
    /**
     * @param owner the owner to set
     */
    public void setOwner(final Account owner) {
        this.owner = owner;
    }
    /**
     * @param ownerAddress the ownerAddress to set
     */
    public void setOwnerAddress(final String ownerAddress) {
        this.ownerAddress = ownerAddress;
    }
    /**
     * @param receivers the receivers to set
     */
    public void setReceivers(final Set<Contact> receivers) {
        this.receivers = receivers;
    }
    /**
     * @param sender the sender to set
     */
    public void setSender(final String sender) {
        this.sender = sender;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(final String title) {
        this.title = title;
    }
}

附件:

// $codepro.audit.disable com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.alwaysOverridetoString.alwaysOverrideToString
/**
 * 
 */
package com.xorty.mailclient.server.domain;

import java.io.Serializable;
import java.sql.SQLException;

import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialException;

import com.xorty.mailclient.client.domain.AttachmentDTO;

/**
 * Heavy weight Hibernate Attachment
 * @author MisoV
 * @version 0.1
 */
public class Attachment implements Serializable {

    private static final long serialVersionUID = 2047475939737947104L;
    private SerialBlob blob;
    private byte[] content;
    private String contentid;
    private String contenttype;
    private String filename;
    private int id;
    private int mailId;


    /**
     *  Hibernate purposes
     */
    public Attachment() { // $codepro.audit.disable emptyMethod
    }

    /**
     * Unwraps DTO to heavy weight hibernate object.
     * @param dto
     */
    public Attachment(final AttachmentDTO dto) {
        content = dto.getContent();
        contentid = dto.getContentid();
        contenttype = dto.getContenttype();
        filename = dto.getFilename();
        id = dto.getId();
        mailId = dto.getMailId();
        try {
            blob = new SerialBlob(content);
        } catch (final SerialException e) {
            e.printStackTrace();
        } catch (final SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * @return the blob
     */
    public SerialBlob getBlob() {
        return blob;
    }

    /**
     * @return the content
     */
    public byte[] getContent() {
        return content;
    }

    /**
     * @return the contentid
     */
    public String getContentid() {
        return contentid;
    }
    /**
     * @return the contenttype
     */
    public String getContenttype() {
        return contenttype;
    }
    /**
     * @return the filename
     */
    public String getFilename() {
        return filename;
    }
    /**
     * @return the id
     */
    public int getId() {
        return id;
    }
    /**
     * @return the mailId
     */
    public int getMailId() {
        return mailId;
    }
    /**
     * @param blob the blob to set
     */
    public void setBlob(final SerialBlob blob) {
        this.blob = blob;
    }
    /**
     * @param content the content to set
     */
    public void setContent(final byte[] content) {
        this.content = content;
    }
    /**
     * @param contentid the contentid to set
     */
    public void setContentid(final String contentid) {
        this.contentid = contentid;
    }
    /**
     * @param contenttype the contenttype to set
     */
    public void setContenttype(final String contenttype) {
        this.contenttype = contenttype;
    }
    /**
     * @param filename the filename to set
     */
    public void setFilename(final String filename) {
        this.filename = filename;
    }

    /**
     * @param id the id to set
     */
    public void setId(final int id) {
        this.id = id;
    }

    /**
     * @param mailId the mailId to set
     */
    public void setMailId(final int mailId) {
        this.mailId = mailId;
    }


}

EDIT2:

Hibernate实际执行insert:

insert into Attachment (name, file, mail_idmail, idAttachment) values (?, ?, ?, ?)

正确设置值。它在session.save和session.get上都没有失败(它甚至可以获得正确的副本)。它在提交交易时失败。

我唯一可以得到的是:Cannot add or update a child row: a foreign key constraint fails ( maildb .附件, CONSTRAINT fk_Attachment_mail1 FOREIGN KEY ( mail_idmail ) REFERENCES mail ( idmail {{ 1}}

2 个答案:

答案 0 :(得分:2)

您收到约束违规例外。我认为这是从附件到邮件的外键,如

所示
foreign key constraint fails (`maildb`.`attachment`, CONSTRAINT `fk_Attachment_mail1` FOREIGN KEY (`mail_idmail`)

我注意到你没有为你的id指定一个生成器。请参阅此文档

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id

由于您没有指定生成器,因此默认为“已分配”,这意味着您必须以编程方式将ID分配给之前保存它们的对象,这可能是也可能不是您想要的。

您没有向我们展示您的邮件实体与附件实体的关系,或者您如何创建实体的代码,这将帮助我更多...取决于您的操作方式,hibernate可能或可能无法在附件类中分配外键。

编辑 - 从你的评论中,你遗漏了一些东西。尝试在邮件的addAttachment方法中将邮件实体的ID分配给附件。如果您希望db分配id,您需要查找如何让表的id列自动增加您正在使用的任何RDBMS系统,然后更改添加生成器到实体的id映射。根据RDBMS,生成器可能是“标识”或“增量”。

答案 1 :(得分:0)

如果您想建立双向关系,您应该向您的附件指明Mail对象,而不仅仅是Id:

在Attcahment类中,删除

  

private int mailId;   并替换它   私人邮件;

使用正确的setter和getter。

在Xml映射文件中:

<property name="mailId">
    <column name="mail_idmail"></column>
</property>

应替换为:

<many-to-one name="mail"
             column="mail_idmail" not-null="true"/>

顺便说一下,你的hashCode / equals方法是垃圾。 你应该读这个:http://community.jboss.org/wiki/EqualsandHashCode 无论如何,最好不要覆盖它们而不是错误。