Hibernate:org.hibernate.NonUniqueObjectException

时间:2017-01-27 22:49:59

标签: hibernate join hibernate-mapping

我正在使用hibernate来处理数据库事务。

我有2个实体:

  • SegmentFileEntity

  • SegmentFileMappingEntity

SegmentFileEntity可以有一个或多个SegmentFileMappingEntity。 Join键是SEGMENT_FILE_ID,它是

中的主键

SegmentFileEntity的相关表格结构:

CREATE TABLE OAP_META_NEW.SEGMENT_FILE
(
  SEGMENT_FILE_ID    NUMBER(10)                 DEFAULT OAP_META_NEW.SEGMENT_FILE_SEQ.NEXTVAL CONSTRAINT SEGMENTFILEID_NOTNULL NOT NULL,
  SEGMENT_FILE_PATH  VARCHAR2(500 BYTE)         CONSTRAINT SEGMENTFILEPATH_NOTNULL NOT NULL,
  CLIENT_ID          NUMBER(10)                 CONSTRAINT SEGMENTFILE_CLIENTID_NOTNULL NOT NULL,
  INSERT_DATE        DATE                       NOT NULL
)

该表上的约束细节:

[![在此处输入图像说明] [1]] [1]

SegmentFileMappingEntity的相关表格结构:

CREATE TABLE OAP_META_NEW.SEGMENT_FILE_MAPPING
(
  SEGMENT_FILE_MAPPING_ID  NUMBER(10)           DEFAULT OAP_META_NEW.SEGMENT_FILE_MAPPING_SEQ.NEXTVAL CONSTRAINT SFM_SFMID_NOTNULL NOT NULL,
  SEGMENT_FILE_ID          NUMBER(10) CONSTRAINT SFM_SEGMENTFILEID_NOTNULL NOT NULL,
  ATTRIBUTE_POSITION       NUMBER(3) CONSTRAINT SFM_ATTRIBUTEPOSITION_NOTNULL NOT NULL,
  ATTRIBUTE_NAME           VARCHAR2(100 BYTE) CONSTRAINT SFM_ATTRIBUTENAME_NOTNULL NOT NULL
)

该表上约束的细节:

[![在此处输入图像说明] [2]] [2]

以下是我在这些实体上运行的测试:

public class SegmentFileTest
    extends AbstractTest
{
    private long attCatId;
    private int attCatTypeId;
    private long attDelimitedSavedId;
    private long attFixedSavedId;
    private long attDerivedSavedId;

    SegmentFileService segmentFileService;

    @BeforeClass
    public void setUpAttributeCategoryTypeAttributeCategory()
    {
        segmentFileService = context.getBean( SegmentFileService.class );


    }

    @Test
    public void saveSegmentFile()
    {

        //Create segment-file
        SegmentFileEntity segmentFile = new SegmentFileEntity();
        segmentFile.setClientId( 0 );
        segmentFile.setSegmentFilePath( "/fakepath/" );
        segmentFile.setInsertDate( new Date((new java.util.Date()).getTime()));

        //Create segment-file-mapping
        List<SegmentFileMappingEntity> fileMappings = new ArrayList<SegmentFileMappingEntity>( );

        SegmentFileMappingEntity segmentFileMapping1 = new SegmentFileMappingEntity();
        segmentFileMapping1.setAttributeName( "attr1" );
        segmentFileMapping1.setAttributePosition( 1 );

        SegmentFileMappingEntity segmentFileMapping2 = new SegmentFileMappingEntity();
        segmentFileMapping2.setAttributeName( "attr2" );
        segmentFileMapping2.setAttributePosition( 2 );

        fileMappings.add(segmentFileMapping1);
        fileMappings.add(segmentFileMapping2);

        segmentFile.setSegmentFileAttributeMappings( fileMappings );
        segmentFileService.saveSegmentFileEntity( segmentFile );


    }
}

问题:

如果我在保存SegmentFileEntity时只使用1个SegmentFileMappingEntity,那很好。但如果我使用超过1个SegmentFileMappingEntity,同时保存SegmentFileEntity,我看到错误:

org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session. Any insight?

以下是我的java-hibernate实体:

** SegmentFileEntity:**

package com.company.online.segment.api.entities;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Date;
import java.util.Collection;
import java.util.List;




@Entity
@Table( name = "SEGMENT_FILE", schema = "OAP_META_NEW" )
@SequenceGenerator( name = "segment_file_seq", sequenceName = "OAP_META_NEW.SEGMENT_FILE_SEQ" )
public class SegmentFileEntity implements Serializable
{

    private int segmentFileId;
    private String segmentFilePath;
    private int clientId;
    private Date insertDate;

    @Id
    @Column( name = "SEGMENT_FILE_ID" , nullable = false, unique = true, precision = 0 )
    @GeneratedValue( strategy = GenerationType.AUTO, generator = "segment_file_seq" )
    @JoinColumn(name = "SEGMENT_FILE_ID", referencedColumnName = "SEGMENT_FILE_ID")
    public int getSegmentFileId()
    {
        return segmentFileId;
    }

    public void setSegmentFileId( int segmentFileId )
    {
        this.segmentFileId = segmentFileId;
    }

    @Basic @Column( name = "SEGMENT_FILE_PATH" ) public String getSegmentFilePath()
    {
        return segmentFilePath;
    }

    public void setSegmentFilePath( String segmentFilePath )
    {
        this.segmentFilePath = segmentFilePath;
    }

    @Basic @Column( name = "CLIENT_ID" ) public int getClientId()
    {
        return clientId;
    }

    public void setClientId( int clientId )
    {
        this.clientId = clientId;
    }

    @Basic @Column( name = "INSERT_DATE" )
    public Date getInsertDate()
    {
        return insertDate;
    }

    public void setInsertDate( Date insertDate )
    {
        this.insertDate = insertDate;
    }

    @Override public boolean equals( Object o )
    {
        if ( this == o )
            return true;
        if ( o == null || getClass() != o.getClass() )
            return false;

        SegmentFileEntity that = (SegmentFileEntity) o;

        if ( segmentFileId != that.segmentFileId )
            return false;
        if ( clientId != that.clientId )
            return false;
        if ( segmentFilePath != null ? !segmentFilePath.equals( that.segmentFilePath ) : that.segmentFilePath != null )
            return false;
        if ( insertDate != null ? !insertDate.equals( that.insertDate ) : that.insertDate != null )
            return false;

        return true;
    }

    @Override public int hashCode()
    {
        int result = segmentFileId;
        result = 31 * result + ( segmentFilePath != null ? segmentFilePath.hashCode() : 0 );
        result = 31 * result + clientId;
        result = 31 * result + ( insertDate != null ? insertDate.hashCode() : 0 );
        return result;
    }


    private List<SegmentFileMappingEntity> segmentFileAttributeMappings;

    @OneToMany( cascade = CascadeType.ALL, fetch = FetchType.EAGER , orphanRemoval = true )
    @JoinColumn( name = "SEGMENT_FILE_ID", referencedColumnName = "SEGMENT_FILE_ID", nullable = false)
    public List<SegmentFileMappingEntity> getSegmentFileAttributeMappings()
    {
        return segmentFileAttributeMappings;
    }

    public void setSegmentFileAttributeMappings( List<SegmentFileMappingEntity> segmentFileAttributeMappings )
    {
        this.segmentFileAttributeMappings = segmentFileAttributeMappings;
    }
}

SegmentFileMappingEntity:

package com.company.online.segment.api.entities;

import javax.persistence.*;
import java.io.Serializable;


@Entity @Table( name = "SEGMENT_FILE_MAPPING", schema = "OAP_META_NEW" )
public class SegmentFileMappingEntity implements Serializable
{

    private int segmentFileMappingId;
    private int segmentFileId;
    private int attributePosition;
    private String attributeName;

    @Id @Column( name = "SEGMENT_FILE_MAPPING_ID" ) public int getSegmentFileMappingId()
    {
        return segmentFileMappingId;
    }

    public void setSegmentFileMappingId( int segmentFileMappingId )
    {
        this.segmentFileMappingId = segmentFileMappingId;
    }

    @Basic
    @Column( name = "SEGMENT_FILE_ID", nullable = false, precision = 0, updatable = false, insertable = false )
    public int getSegmentFileId()
    {
        return segmentFileId;
    }

    public void setSegmentFileId( int segmentFileId )
    {
        this.segmentFileId = segmentFileId;
    }

    @Basic @Column( name = "ATTRIBUTE_POSITION" ) public int getAttributePosition()
    {
        return attributePosition;
    }

    public void setAttributePosition( int attributePosition )
    {
        this.attributePosition = attributePosition;
    }

    @Basic @Column( name = "ATTRIBUTE_NAME" ) public String getAttributeName()
    {
        return attributeName;
    }

    public void setAttributeName( String attributeName )
    {
        this.attributeName = attributeName;
    }

    @Override public boolean equals( Object o )
    {
        if ( this == o )
            return true;
        if ( o == null || getClass() != o.getClass() )
            return false;

        SegmentFileMappingEntity that = (SegmentFileMappingEntity) o;

        if ( segmentFileMappingId != that.segmentFileMappingId )
            return false;
        if ( segmentFileId != that.segmentFileId )
            return false;
        if ( attributePosition != that.attributePosition )
            return false;
        if ( attributeName != null ? !attributeName.equals( that.attributeName ) : that.attributeName != null )
            return false;

        return true;
    }

    @Override public int hashCode()
    {
        int result = segmentFileMappingId;
        result = 31 * result + segmentFileId;
        result = 31 * result + attributePosition;
        result = 31 * result + ( attributeName != null ? attributeName.hashCode() : 0 );
        return result;
    }
}

1 个答案:

答案 0 :(得分:1)

SegmentFileMappingEntity中,您使用segmentFileMappingId为字段@Id注释了访问者,因此hibernate会将其用作数据库标识符。这意味着它必须对每个对象行都是唯一的。

但你没有为它提供价值。

因此它是一个整数,它的默认值是0,因此在创建对象期间,每个创建的SegmentFileMappingEntity实例都会获得0作为标识符。在您当前的会话/持久性上下文中,这是&#34;意外确定&#34;对于一个条目,不可能保存第二个。

解决方案是为应用程序级别的每个实例生成唯一值,或者让hibernate为您生成一个(就像您已经使用SegmentFileEntity访问者getSegmentFileId()的数据库序列一样)。

有关详细信息,请参阅here