Hibernate отображение проблемы один ко многим - PullRequest
2 голосов
/ 16 января 2011

Я не очень разбираюсь в 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 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 ) ON DELETE NO ACTION ON UPDATE NO ACTION)

Ответы [ 2 ]

2 голосов
/ 16 января 2011

вы получаете исключение нарушения ограничения. Я думаю, что это на внешний ключ от вложения в почту, о чем свидетельствует

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

Я заметил, что вы не указываете генератор для вашего идентификатора. Смотрите эту документацию

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

, так как вы не указали генератор, по умолчанию это «назначено», что означает, что вы должны программно назначать идентификаторы объектам до того, как вы их сохраните, что может быть или не быть тем, что вы хотите.

Вы не показывали нам код того, как ваша сущность Mail относится к сущности Attachment или как вы создаете свои сущности, что может помочь мне больше ... в зависимости от того, как вы это делаете, гибернация может или может не удастся назначить внешний ключ в классе вложения.

РЕДАКТИРОВАТЬ - из ваших комментариев, вам не хватает нескольких вещей. Попробуйте назначить идентификатор почтового объекта вложению в методе addAttachment для почты. Если вы хотите, чтобы БД назначил идентификатор, вам нужно посмотреть, как сделать автоматическое увеличение столбца id таблицы для любой используемой вами системы RDBMS, а затем изменить добавление генератора в отображения идентификаторов сущностей. Генератор, вероятно, будет «тождественным» или «инкрементным» в зависимости от СУБД.

0 голосов
/ 16 января 2011

Поскольку вы хотите установить двунаправленное отношение, вы должны указать своему Приложению объект Mail, а не только Id:

В классе Attcahment удалите

private int mailId;и замените его частной почтой;

с правильными установщиком и получателем.

В файле сопоставления 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 В любом случае, лучше не переопределять их, чем ошибаться.

...