gpt4 book ai didi

带连接表的 Hibernate 一对多 - 重复插入

转载 作者:行者123 更新时间:2023-12-03 06:55:14 25 4
gpt4 key购买 nike

我确信这个问题以前有人问过,但我似乎找不到答案。我正在使用 Hibernate 4.0 来建立基本的关系。我有一个 Person 对象,可以包含可能的地址(是的,从另一个站点获取代码,认为它可以工作,但事实并非如此)。我想使用连接表。我觉得我已经尝试了所有可能的组合,但不断出现相同的错误:“键 1 的‘1-3’重复输入”。基本上是当我在设置双方关系(人员/地址)后尝试提交事务时发生的 Hibernate 错误。显然,它试图插入相同的记录两次,这在连接表中是不允许的,因为 personId/addressId 组合应该只出现一次。任何帮助将不胜感激,也许是一个有效的 Junit 测试。在下面的相同内容中,我手动插入了一个人和三个地址,前两个已经与该人相关。

1) 我是否必须明确设置双方的关系(人员和地址)?似乎不对,因为这样其他对象之一就会不同步。2)为什么如果我使用 List 而不是 Set 就可以正常工作?

单元测试:

@Test
public void tryAgain(){
Person p = em.find(Person.class, 1);<br>
Address a = em.find(Address.class, 1);<br>
Address b= em.find(Address.class,2);<br>
Address c= em.find(Address.class, 3);<br>
em.getTransaction().begin();<br>
p.addresses.add(c);<br>
c.person=p;<br>
em.getTransaction().commit();<br>
assertTrue(p.addresses.size()==3);<br>
}


JUnit 堆栈跟踪

Hibernate: select person0_.personId as personId3_0_ from PERSON person0_ where person0_.personId=?
<br>Hibernate: select address0_.addressId as addressId6_1_, address0_1_.personId as personId7_1_, person1_.personId as personId3_0_ from ADDRESS address0_ left outer join PersonAddress address0_1_ on address0_.addressId=address0_1_.addressId left outer join PERSON person1_ on address0_1_.personId=person1_.personId where address0_.addressId=?
<br>Hibernate: select address0_.addressId as addressId6_1_, address0_1_.personId as personId7_1_, person1_.personId as personId3_0_ from ADDRESS address0_ left outer join PersonAddress address0_1_ on address0_.addressId=address0_1_.addressId left outer join PERSON person1_ on address0_1_.personId=person1_.personId where address0_.addressId=?
<br>Hibernate: select address0_.addressId as addressId6_1_, address0_1_.personId as personId7_1_, person1_.personId as personId3_0_ from ADDRESS address0_ left outer join PersonAddress address0_1_ on address0_.addressId=address0_1_.addressId left outer join PERSON person1_ on address0_1_.personId=person1_.personId where address0_.addressId=?
<br>Hibernate: select addresses0_.personId as personId3_2_, addresses0_.addressId as addressId2_, address1_.addressId as addressId6_0_, address1_1_.personId as personId7_0_, person2_.personId as personId3_1_ from PersonAddress addresses0_ inner join ADDRESS address1_ on addresses0_.addressId=address1_.addressId left outer join PersonAddress address1_1_ on address1_.addressId=address1_1_.addressId left outer join PERSON person2_ on address1_1_.personId=person2_.personId where addresses0_.personId=?
<b>Hibernate: insert into PersonAddress (personId, addressId) values (?, ?)
<br>Hibernate: insert into PersonAddress (personId, addressId) values (?, ?)</b>
<br>Dec 26, 2011 10:40:27 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions

警告:SQL 错误:1062,SQLState:23000
2011 年 12 月 26 日 10:40:27 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions错误: key 1 的条目“1-3”重复

代码

@Entity<br>
@Table(name="PERSON")<br>
public class Person {<br>
@Id<br>
@GeneratedValue(strategy = GenerationType.AUTO)<br>
@Column(name = "personId")<br>
public int id;<br>
@OneToMany()<br>
@JoinTable(name = "PersonAddress",
joinColumns = {
@JoinColumn(name="personId", unique = true)},
inverseJoinColumns = {
@JoinColumn(name="addressId")})<br>
public Set<Address> addresses = new HashSet<Address>();<br>
}


@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "addressId")
public int id;

@ManyToOne(optional=true,cascade={CascadeType.ALL})
@JoinTable(name = "PersonAddress",
joinColumns = {@JoinColumn(name="addressId",insertable=false,updatable=true)},
inverseJoinColumns = {
@JoinColumn(name="personId")
})
public Person person;
}

最佳答案

开发的关键原则之一是 DRY:不要重复自己。 JPA 应用它,因此当您有双向关联时,您应该仅在关联的一侧声明该关联的映射一次。另一方应该只说:我使用mappedBy 属性按照另一方声明进行映射。

由于您映射了双向关联两次,Hibernate 认为您有两个不同的关联,因此进行两次插入。

地址集的声明方式如下:

@OneToMany(mappedBy = "person")
private Set<Address> addresses = new HashSet<Address>();

其他备注:

  • OO 的另一个关键原则是封装。您的字段应该是私有(private)的
  • 在 toOne 关系上使用 Cascade = ALL 总是错误的:您真的希望在某个人的地址被删除时也将其删除吗?
  • 如果关联是双向的,为什么要使用连接表?为什么不直接对地址中的人员使用外键?

关于带连接表的 Hibernate 一对多 - 重复插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8641322/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com