Hibernate:发现具有给定标识符的多行错误
我正在使用Spring4.0.5和Hibernate4.3.5;我在hibernate中遇到了一个错误,我不知道我错在哪里(因为我肯定我错了)。我有一个与其相关的表,它表示一个web树,其中每个根节点可以有几个子节点,因此我创建了这个类: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) @
@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;