问题描述
我有两个具有一对多关系的实体,如下所示.一切正常,除了删除动作.删除时,出现错误:关系"a_b"不存在.为此,我在在此处找到了解决方案.
I have two entities with one to many relationships as below. Everything works fine except delete action. On deleting, I was getting ERROR: relation "a_b" does not exist. For that, I found the solution here.
根据一个答案,该关系存在问题,并且 hibernate将关系视为单独的单向关系,它将创建第三个表a_b并独立跟踪关系的两侧.为了解决该问题,我添加了 mappedBy ="a" .
According to an answer, there was an issue with the relationship and hibernate treats relationships as separate uni-directional relationships and it will create the third table a_b and tracks both sides of the relationship independently. To resolve the issue I had added mappedBy = "a".
问题是
为什么在创建新记录时,休眠状态会触发对表a_b的删除查询,而该查询没有插入到a_b中呢?
登录插入
Hibernate: insert into a...
Hibernate: insert into b...
Hibernate: insert into b...
Hibernate: insert into b...
**Why insert into a_b... is not generated/inserted?**
登录删除
Hibernate: select a0_.id as id1_11_, from a a0_ where (a0_.id in (?))?
Hibernate: delete from b where a_id in (?)
Hibernate: delete from a_b where (a_id) in (select id from a where id in (?))
**Why delete from a_b if nothing is inserted into a_b**
12:19:50.432 [XNIO-1 task-20] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 0, SQLState: 42P01
12:19:50.433 [XNIO-1 task-20] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: relation "a_b" does not exist
with cause = 'org.hibernate.exception.SQLGrammarException: could not execute statement' and exception = 'could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement'
实体A
@Entity
@Table(name = "a")
public class A extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@OneToMany
private List<B> b;
.....
}
实体B
@Entity
@Table(name = "b")
public class B extends AbstractAuditingEntity implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@ManyToOne
private A a;
.....
}
AServiceImpl
@Override
public int delete(List<Long> ids) {
...
bRepository.deleteWithIds(ids);
aRepository.deleteWithIds(ids);
}
B存储库
@Transactional
@Modifying
@Query("delete from b x where x.a.id in :ids")
void deleteLogsWithIds(@Param("ids") List<Long> ids);
存储库
@Modifying
@Transactional
@Query("delete from a x where x.id in :ids")
void deleteJobWithIds(@Param("ids") List<Long> ids);
当前代码
实体A
@Entity
@Table(name = "a")
public class A extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@OneToMany(mappedBy = "a")
private List<B> b;
.....
}
实体B
@Entity
@Table(name = "b")
public class B extends AbstractAuditingEntity implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
@SequenceGenerator(name = "sequenceGenerator")
private Long id;
@ManyToOne
private A a;
.....
}
插入序列
-
保存实体A
Save Entity A
aRepository.saveAndFlush(a);
基于响应集Entity A调用第三方API用于保存实体B
Make a call to third party API and based on response set Entity Afor saving Entity B
x.forEach(b-> { b.setA(aRepository.findById(aId).get()); bRepository.save(b); });
x.forEach(b-> { b.setA(aRepository.findById(aId).get()); bRepository.save(b); });
推荐答案
可以考虑许多方案如果您使用的是单向映射,则将需要一个联接表来保存关系.由于单个A实体与多个B实体相关联,并且由于其单向性,它没有B表中的映射列.enter code here
There can be many scenarios to considerIf you are using a uni-directional oneToMany mapping it will require a join table to save the relationship.Since, a single A entity is associated with multiple B entities and due to its unidirectional nature it does not has a mapping column in B table.enter code here
@Entity
@Table(name = "A")
public class A {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private int id;
private String stateName;
//This is uni-directional since we donot have a corresponding reference to A in B entity
@OneToMany(cascade = CascadeType.ALL)
List<B> bs = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<B> getBs() {
return bs;
}
public void setBs(List<B> bs) {
this.bs = bs;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
}
@Entity
@Table(name="B")
public class B {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="ID")
private int id;
private String districtName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDistrictName() {
return districtName;
}
public void setDistrictName(String districtName) {
this.districtName = districtName;
}
}
在上述情况下,它是单向的oneToMany,它将需要一个联接表.
In the above case its uni-directional oneToMany and it will require a join-table.
如果您这样保存实体 enter code here
If you save your entity like this enter code here
A a= new A();
B b=new B();
B b1=new B();
List<B> bs=new ArrayList<>();
bs.add(b);
bs.add(b1);
aRepository.save(a);
这会将关系映射保存在联接表中.
This will save the relationship mapping in join table.
案例2 :-现在,如果在B实体类中添加以下内容,它将为A表创建一个外键列.这将再次是单向的ManyToOne映射.
Case 2:- Now if you add the following in the B entity class it will create a foreign-key column to A table. This will be again a unidirection ManyToOne mapping.
enter code here
@ManyToOne()
A a;
如果您遵循
enter code here
A a =new A();
B b =new B();
b.setA(a);
B b1=new B();
b1.setA(a);
bRepository.save(b);
bRepository.save(b1);
这不会将关系保存在联接表中,而是将使用表B列中名为A_ID的外键.
This will not save the relationship in the join table instead it will use the foreign-key which is present in the table B column named A_ID.
案例3:-双向oneToMany
enter code here
@Entity
@Table(name = "A")
public class A {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private int id;
private String stateName;
@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
List<B> bs = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<B> getBs() {
return bs;
}
public void setBs(List<B> bs) {
this.bs = bs;
}
public void addB(B b) {
b.setA(this);
bs.add(b);
}
public void removeB(B b) {
b.setA(null);
bs.remove(b);
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
}
@Entity
@Table(name = "B")
public class B {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private int id;
private String districtName;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "A_ID")
A a;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public String getDistrictName() {
return districtName;
}
public void setDistrictName(String districtName) {
this.districtName = districtName;
}
}
以上实体映射是双向的oneToMany,并且不使用联接表.
The above entity mapping is bi-directional oneToMany and doesn't uses the join-table.
这篇关于了解休眠连接表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!