Hibernate:发现具有给定标识符的多行错误

Hibernate:发现具有给定标识符的多行错误,hibernate,Hibernate,我正在使用Spring4.0.5和Hibernate4.3.5;我在hibernate中遇到了一个错误,我不知道我错在哪里(因为我肯定我错了)。我有一个与其相关的表,它表示一个web树,其中每个根节点可以有几个子节点,因此我创建了这个类: @DynamicUpdate @Cache(region = "it.eng.angelo.spring.dao.hibernate.models.WebTree", usage = CacheConcurrencyStrategy.READ_WRITE) @

我正在使用Spring4.0.5和Hibernate4.3.5;我在hibernate中遇到了一个错误,我不知道我错在哪里(因为我肯定我错了)。我有一个与其相关的表,它表示一个web树,其中每个根节点可以有几个子节点,因此我创建了这个类:

@DynamicUpdate
@Cache(region = "it.eng.angelo.spring.dao.hibernate.models.WebTree", usage = CacheConcurrencyStrategy.READ_WRITE)
@Entity
@Table(name = "MEDIA_GALL_TREE", indexes = {@Index(name = "NOME_FOLDER_IDX", columnList = "NOME_FOLDER")})
public class WebTree extends AbstractModel
{

    private static final long serialVersionUID = -4572195412018767502L;
    private long id;
    private String text;
    private boolean opened;
    private boolean disabled;
    private boolean selected;
    private Set<WebTree> children = new HashSet<WebTree>(0);
    private Set<Media> media = new HashSet<Media>(0);
    private WebTree father;
    private WcmDomain dominio;
    public WebTree()
    {
        super();
    }
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID_FOLDER", unique = true, nullable = false)
    public long getId()
    {
        return id;
    }
    public void setId(long id)
    {
        this.id = id;
    }
    @Column(name = "NOME_FOLDER", nullable = false, unique=false)
    public String getText()
    {
        return text;
    }
    public void setText(String text)
    {
        this.text = text;
    }
    @Column(name = "OPENED_FOLDER")
    public boolean isOpened()
    {
        return opened;
    }
    public void setOpened(boolean opened)
    {
        this.opened = opened;
    }
    @Column(name = "DISABLED_FOLDER")
    public boolean isDisabled()
    {
        return disabled;
    }
    public void setDisabled(boolean disabled)
    {
        this.disabled = disabled;
    }
    @Column(name = "SELECTED_FOLDER")
    public boolean isSelected()
    {
        return selected;
    }
    public void setSelected(boolean selected)
    {
        this.selected = selected;
    }
    @OneToMany(mappedBy = "father", orphanRemoval = true, targetEntity = WebTree.class)
    public Set<WebTree> getChildren()
    {
        return children;
    }
    public void setChildren(Set<WebTree> children)
    {
        this.children = children;
    }
    @ManyToOne(targetEntity = WebTree.class)
    @JoinColumn(name = "ID_PADRE", nullable = true)
    public WebTree getFather()
    {
        return father;
    }
    public void setFather(WebTree father)
    {
        this.father = father;
    }
    @OneToOne
    @JoinColumn(name="ID_DOMINIO", nullable=false)
    public WcmDomain getDominio()
    {
        return dominio;
    }
    public void setDominio(WcmDomain dominio)
    {
        this.dominio = dominio;
    }
    @OneToMany( mappedBy = "folder", orphanRemoval = true, targetEntity = Media.class, cascade = { CascadeType.ALL })
    public Set<Media> getMedia()
    {
        return media;
    }
    public void setMedia(Set<Media> media)
    {
        this.media = media;
    }

}
执行代码时,hibernate打印以下查询:

Hibernate: 
    select
        this_.ID_FOLDER as ID_FOLDE1_7_2_,
        this_.UT_INS as UT_INS2_7_2_,
        this_.DT_INS as DT_INS3_7_2_,
        this_.DT_UPD as DT_UPD4_7_2_,
        this_.UT_UPD as UT_UPD5_7_2_,
        this_.DISABLED_FOLDER as DISABLED6_7_2_,
        this_.ID_DOMINIO as ID_DOMI10_7_2_,
        this_.ID_PADRE as ID_PADR11_7_2_,
        this_.OPENED_FOLDER as OPENED_F7_7_2_,
        this_.SELECTED_FOLDER as SELECTED8_7_2_,
        this_.NOME_FOLDER as NOME_FOL9_7_2_,
        wcmdomain2_.ID_DOMINIO as ID_DOMIN1_8_0_,
        wcmdomain2_.UT_INS as UT_INS2_8_0_,
        wcmdomain2_.DT_INS as DT_INS3_8_0_,
        wcmdomain2_.DT_UPD as DT_UPD4_8_0_,
        wcmdomain2_.UT_UPD as UT_UPD5_8_0_,
        wcmdomain2_.WCM_NOME_DOMINIO as WCM_NOME6_8_0_,
        mediagalle3_.ID_FOLDER as ID_FOLDE1_7_1_,
        mediagalle3_.UT_INS as UT_INS2_7_1_,
        mediagalle3_.DT_INS as DT_INS3_7_1_,
        mediagalle3_.DT_UPD as DT_UPD4_7_1_,
        mediagalle3_.UT_UPD as UT_UPD5_7_1_,
        mediagalle3_.DISABLED_FOLDER as DISABLED6_7_1_,
        mediagalle3_.ID_DOMINIO as ID_DOMI10_7_1_,
        mediagalle3_.ID_PADRE as ID_PADR11_7_1_,
        mediagalle3_.OPENED_FOLDER as OPENED_F7_7_1_,
        mediagalle3_.SELECTED_FOLDER as SELECTED8_7_1_,
        mediagalle3_.NOME_FOLDER as NOME_FOL9_7_1_ 
    from
        MEDIA_GALL_TREE this_ 
    inner join
        WCM_DOMAIN wcmdomain2_ 
            on this_.ID_DOMINIO=wcmdomain2_.ID_DOMINIO 
    left outer join
        MEDIA_GALL_TREE mediagalle3_ 
            on this_.ID_PADRE=mediagalle3_.ID_FOLDER 
    where
        this_.ID_FOLDER=?
Hibernate: 
    select
        mediagalle0_.ID_FOLDER as ID_FOLDE1_7_2_,
        mediagalle0_.UT_INS as UT_INS2_7_2_,
        mediagalle0_.DT_INS as DT_INS3_7_2_,
        mediagalle0_.DT_UPD as DT_UPD4_7_2_,
        mediagalle0_.UT_UPD as UT_UPD5_7_2_,
        mediagalle0_.DISABLED_FOLDER as DISABLED6_7_2_,
        mediagalle0_.ID_DOMINIO as ID_DOMI10_7_2_,
        mediagalle0_.ID_PADRE as ID_PADR11_7_2_,
        mediagalle0_.OPENED_FOLDER as OPENED_F7_7_2_,
        mediagalle0_.SELECTED_FOLDER as SELECTED8_7_2_,
        mediagalle0_.NOME_FOLDER as NOME_FOL9_7_2_,
        wcmdomain1_.ID_DOMINIO as ID_DOMIN1_8_0_,
        wcmdomain1_.UT_INS as UT_INS2_8_0_,
        wcmdomain1_.DT_INS as DT_INS3_8_0_,
        wcmdomain1_.DT_UPD as DT_UPD4_8_0_,
        wcmdomain1_.UT_UPD as UT_UPD5_8_0_,
        wcmdomain1_.WCM_NOME_DOMINIO as WCM_NOME6_8_0_,
        mediagalle2_.ID_FOLDER as ID_FOLDE1_7_1_,
        mediagalle2_.UT_INS as UT_INS2_7_1_,
        mediagalle2_.DT_INS as DT_INS3_7_1_,
        mediagalle2_.DT_UPD as DT_UPD4_7_1_,
        mediagalle2_.UT_UPD as UT_UPD5_7_1_,
        mediagalle2_.DISABLED_FOLDER as DISABLED6_7_1_,
        mediagalle2_.ID_DOMINIO as ID_DOMI10_7_1_,
        mediagalle2_.ID_PADRE as ID_PADR11_7_1_,
        mediagalle2_.OPENED_FOLDER as OPENED_F7_7_1_,
        mediagalle2_.SELECTED_FOLDER as SELECTED8_7_1_,
        mediagalle2_.NOME_FOLDER as NOME_FOL9_7_1_ 
    from
        MEDIA_GALL_TREE mediagalle0_ 
    inner join
        WCM_DOMAIN wcmdomain1_ 
            on mediagalle0_.ID_DOMINIO=wcmdomain1_.ID_DOMINIO 
    left outer join
        MEDIA_GALL_TREE mediagalle2_ 
            on mediagalle0_.ID_PADRE=mediagalle2_.ID_FOLDER 
    where
        mediagalle0_.ID_DOMINIO=?
这些是我的表格记录:

id_folder; ut_ins; dt_ins; dt_upd; ut_upd; disabled_folder; opened_folder; selected_folder; nome_folder; id_dominio; id_padre
"1";"system";"2014-06-12 18:23:16.649";"2014-06-12 18:23:16.649";"system";FALSE;FALSE;FALSE;"Root 1";1;
"2";"system";"2014-06-12 18:23:16.662";"2014-06-12 18:23:16.662";"system";FALSE;FALSE;FALSE;"Root 2";2;
"4";"wpsAdmin";"2014-06-13 16:18:01.428";"2014-06-13 18:12:14.228";"wpsAdmin";FALSE;FALSE;FALSE;"Testina";2;2
"7";"wpsAdmin";"2014-06-13 17:33:05.575";"2014-06-13 17:33:10.275";"wpsAdmin";FALSE;FALSE;FALSE;"Angelo";2;2
谁能告诉我哪里错了?在我看来这一切都是正确的……欢迎提供任何提示

多谢各位 安杰洛

请注意:如果我以这种方式使用我的POJO类方法getChildern,那么所有这些都非常有效:

@OneToMany( mappedBy = "father", targetEntity = WebTree.class, fetch=FetchType.EAGER)
public Set<WebTree> getChildren()
{
    return children;
}
@OneToMany(mappedBy=“father”,targetEntity=WebTree.class,fetch=FetchType.EAGER)
公共集getChildren()
{
返回儿童;
}
但我想知道为什么会有这种行为

多谢各位
安杰洛

我很抱歉;这是我的错误……在我的实体类中,我错误地将一个关系映射为oneToOne;相反,它是一家公司:) 现在一切都很好。。。。。;这是我的新实体类:

@DynamicUpdate
@Cache(region = "it.eng.angelo.spring.dao.hibernate.models.MediaGalleryTree", usage = CacheConcurrencyStrategy.READ_WRITE)
@Entity
@Table(name = "MEDIA_GALL_TREE", indexes = {@Index(name = "NOME_FOLDER_IDX", columnList = "NOME_FOLDER")})
public class MediaGalleryTree extends AbstractModel
{

    private static final long serialVersionUID = -4572195412018767502L;
    private long id;
    private String text;
    private boolean opened;
    private boolean disabled;
    private boolean selected;
    private Set<MediaGalleryTree> children = new HashSet<MediaGalleryTree>(0);
    private Set<FedoraCommonsEntity> media = new HashSet<FedoraCommonsEntity>(0);
    private MediaGalleryTree father;
    private WcmDomain dominio;
    public MediaGalleryTree()
    {
        super();
    }
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID_FOLDER", unique = true, nullable = false)
    public long getId()
    {
        return id;
    }
    public void setId(long id)
    {
        this.id = id;
    }
    @Column(name = "NOME_FOLDER", nullable = false, unique=false)
    public String getText()
    {
        return text;
    }
    public void setText(String text)
    {
        this.text = text;
    }
    @Column(name = "OPENED_FOLDER")
    public boolean isOpened()
    {
        return opened;
    }
    public void setOpened(boolean opened)
    {
        this.opened = opened;
    }
    @Column(name = "DISABLED_FOLDER")
    public boolean isDisabled()
    {
        return disabled;
    }
    public void setDisabled(boolean disabled)
    {
        this.disabled = disabled;
    }
    @Column(name = "SELECTED_FOLDER")
    public boolean isSelected()
    {
        return selected;
    }
    public void setSelected(boolean selected)
    {
        this.selected = selected;
    }
    @OneToMany( mappedBy = "father", orphanRemoval = true, 
                targetEntity = MediaGalleryTree.class)
    public Set<MediaGalleryTree> getChildren()
    {
        return children;
    }
    public void setChildren(Set<MediaGalleryTree> children)
    {
        this.children = children;
    }
    @ManyToOne(targetEntity = MediaGalleryTree.class)
    @JoinColumn(name = "ID_PADRE", nullable = true)
    public MediaGalleryTree getFather()
    {
        return father;
    }
    public void setFather(MediaGalleryTree father)
    {
        this.father = father;
    }
    @ManyToOne(targetEntity = WcmDomain.class, cascade={CascadeType.ALL})
    @JoinColumn(name="ID_DOMINIO", nullable=false)
    public WcmDomain getDominio()
    {
        return dominio;
    }
    public void setDominio(WcmDomain dominio)
    {
        this.dominio = dominio;
    }
    @OneToMany( mappedBy = "folder", orphanRemoval = true, 
            targetEntity = Media.class, cascade = { CascadeType.ALL })
    public Set<FedoraCommonsEntity> getMedia()
    {
        return media;
    }
    public void setMedia(Set<FedoraCommonsEntity> media)
    {
        this.media = media;
    }

}
@DynamicUpdate
@Cache(region=“it.eng.angelo.spring.dao.hibernate.models.MediaGalleryTree”,用法=cacheconcurrentystrategy.READ\u-WRITE)
@实体
@表(name=“MEDIA\u GALL\u TREE”,Index={@Index(name=“NOME\u FOLDER\u IDX”,columnList=“NOME\u FOLDER”)})
公共类MediaGalleryTree扩展了抽象模型
{
私有静态最终长serialVersionUID=-4572195412018767502L;
私人长id;
私有字符串文本;
私有布尔开放;
私有布尔禁用;
选择私有布尔值;
私有集子项=新哈希集(0);
私有集媒体=新哈希集(0);
私家咖啡树父亲;
多米尼奥私营WCM域名;
公共媒体目录树()
{
超级();
}
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
@列(name=“ID\u FOLDER”,unique=true,nullable=false)
公共长getId()
{
返回id;
}
公共无效集合id(长id)
{
this.id=id;
}
@列(name=“NOME_FOLDER”,null=false,unique=false)
公共字符串getText()
{
返回文本;
}
公共void setText(字符串文本)
{
this.text=文本;
}
@列(name=“打开的文件夹”)
公共布尔值
{
返回打开;
}
已打开公共void集合(已打开布尔值)
{
this.opened=opened;
}
@列(name=“禁用的文件夹”)
公共布尔值已禁用()
{
返回残疾人;
}
公共无效集禁用(布尔禁用)
{
this.disabled=禁用;
}
@列(name=“所选文件夹”)
公选
{
返回选中的;
}
已选择公共无效设置(已选择布尔值)
{
this.selected=selected;
}
@OneToMany(mappedBy=“父”,orphan=true,
targetEntity=MediaGalleryTree.class)
公共集getChildren()
{
返回儿童;
}
公共无效集合子对象(集合子对象)
{
这个。孩子=孩子;
}
@manytone(targetEntity=MediaGalleryTree.class)
@JoinColumn(name=“ID\u PADRE”,nullable=true)
公共MediaGalleryTree getDather()
{
回归父亲;
}
公共无效集合父(MediaGalleryTree父)
{
这个。父亲=父亲;
}
@manytone(targetEntity=WcmDomain.class,cascade={CascadeType.ALL})
@JoinColumn(name=“ID\u DOMINIO”,nullable=false)
公共WcmDomain getDominio()
{
归还多米尼奥;
}
塞多明诺(WcmDomain dominio)公共空间
{
this.dominio=dominio;
}
@OneToMany(mappedBy=“folder”,orphanRemoving=true,
targetEntity=Media.class,cascade={CascadeType.ALL})
公共集getMedia()
{
返回媒体;
}
公共无效设置媒体(设置媒体)
{
这个.媒体=媒体;
}
}

Angelo

在hibernate中查找一对一的关系映射,然后在数据库中的关联表中查找,可能是关系表获取了多行

我通过
org.hibernate.hibernate获取了位异常:发现了多行具有给定标识符:
问题,并且没有找到有关StackOverflow的帮助。解决这个问题花了一段时间,所以我在这里记录解决方案。我使用的是JPA/Hibernate和Spring数据

首先,这不是由数据库中的重复行引起的,因为显然不可能有重复的主键。相反,这是由于Hibernate查找对象,并急切地用左外部联接填充一对一关系造成的。Hibernate假设返回一行,但返回两行是因为有两个对象与一对一关系相关联

以下是我的对象的简化版本:

@Entity
@Table(name = "plate")
public class Plate {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name="test_seq", sequenceName="test_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test_seq")
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "object_version")
    private long objectVersion;

    @Column(name = "name")
    private String name;

    @OneToOne(mappedBy = "plate")
    private Sheet sheet;

    public Sheet getSheet() {
        return sheet;
    }

    public void setSheet(Sheet sheet) {
        if (this.sheet != null) {
            this.sheet.setPlate(null);
        }

        this.sheet = sheet;
        sheet.setPlate(this);
    }
}


@Entity
@Table(name = "sheet")
public class Sheet {
    private static final long serialVersionUID = 1L;

    @Id
    @SequenceGenerator(name="test_seq", sequenceName="test_seq")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test_seq")
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "object_version")
    private long objectVersion;

    @Column(name = "sheet_name")
    private String sheetName;

    @OneToOne
    @JoinColumn(name = "plate_id")
    private Plate plate;

    public Plate getPlate() {
        return plate;
    }

    // Do not use. Use Plate.setSheet() instead
    void setPlate(Plate plate) {
        this.plate = plate;
    }
}
问题在于板材和板材之间的@OneToOne关系。我最初不想删除孤立图纸。在我的代码中,我按id查找了一个车牌,并添加了一张新的车牌。这将从原始图纸中删除板与图纸的关系。当我提交事务时,我假设JPA将保存所有修改过的对象(图版、原始图纸和新图纸)

这不是真的!JPA显然是通过从最初加载的对象(图版)沿着层次结构向下走找到修改过的对象,它忽略了原来的图纸(现在是孤立的)被修改的事实。这意味着数据库中未清除原始图纸的Sheet.plate_id列。换句话说,我在数据模型中破坏了它们之间的关系,但它无法保存到数据库中。因此,下次我尝试加载平板时,Hibernate会运行如下查询:

select
    plate1_.id as id1_19_12_, 
    plate1_.object_version as object_v2_19_12_, 
    plate1_.name as name3_19_12_, 
    sheet2_.id as id1_39_12_, 
    sheet2_.object_version as object_v2_39_12_, 
    sheet2_.sheet_name as sheet_nam2_39_12_, 
    sheet2_.plate_id as plate_id4_39_12_, 
from 
    plate plate1_
    left outer join sheet sheet2_ on plate1_.id = sheet2_.plate_id
where 
    plate1_.id=?
这将返回结果集中的2行并产生此错误:

org.hibernate.HibernateException: More than one row with the given identifier was found: 10045, for class: com.example.Plate
这是欺骗性的:数据库中只有一行具有该id的板材,但有两张板材链接到它

解决方案: 看来我
select
    plate1_.id as id1_19_12_, 
    plate1_.object_version as object_v2_19_12_, 
    plate1_.name as name3_19_12_, 
    sheet2_.id as id1_39_12_, 
    sheet2_.object_version as object_v2_39_12_, 
    sheet2_.sheet_name as sheet_nam2_39_12_, 
    sheet2_.plate_id as plate_id4_39_12_, 
from 
    plate plate1_
    left outer join sheet sheet2_ on plate1_.id = sheet2_.plate_id
where 
    plate1_.id=?
org.hibernate.HibernateException: More than one row with the given identifier was found: 10045, for class: com.example.Plate
@OneToOne(mappedBy = "plate", cascade = CascadeType.ALL, orphanRemoval = true)
private Sheet sheet;
@OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
    @JoinColumn(name="appointmentId", nullable=false, insertable=false, updatable=false)
    private Appointment appointment;
@ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
    @JoinColumn(name="appointmentId", nullable=false, insertable=false, updatable=false)
    private Appointment appointment;