简体   繁体   English

了解 Hibernate 连接表

[英]Understanding Hibernate Junction Table

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 .删除时,我收到错误:关系“a_b”不存在 For that, I found the solution here .为此,我在这里找到了解决方案。

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 .根据答案,关系存在问题, hibernate 将关系视为单独的单向关系,它将创建第三个表 a_b 并独立跟踪关系的双方 To resolve the issue I had added mappedBy = "a" .为了解决这个问题,我添加了mappingBy = "a"

Question is问题是

Why does hibernate fires delete query for table a_b while it does not insert into a_b at the time new record creation?为什么 hibernate 会触发对表 a_b 的删除查询,而在创建新记录时它没有插入到 a_b 中?

Log on insert登录插入

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?**

Log on delete登录删除

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'

Entity A实体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;

    .....

}

Entity 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);
   }

BRepository B存储库

@Transactional
@Modifying
@Query("delete from b x where x.a.id in :ids")
void deleteLogsWithIds(@Param("ids") List<Long> ids);

ARepository存储库

@Modifying
@Transactional
@Query("delete from a x where x.id in :ids")
void deleteJobWithIds(@Param("ids") List<Long> ids);

Current Code当前代码

Entity A实体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;

    .....

}

Entity 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;

        .....
}

EDIT: Insert sequence编辑:插入序列

  1. Save Entity A保存实体 A

    aRepository.saveAndFlush(a);

  2. Make a call to third party API and based on response set Entity A for saving Entity B调用第三方 API 并根据响应集实体 A 保存实体 B

    x.forEach(b-> { b.setA(aRepository.findById(aId).get()); bRepository.save(b); });

There can be many scenarios to consider If 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.可能有很多情况需要考虑如果您使用单向oneToMany 映射,则需要一个连接表来保存关系。因为,单个 A 实体与多个 B 实体相关联,并且由于其单向性质,它没有B表中的一个映射列。 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;
    }
}

In the above case its uni-directional oneToMany and it will require a join-table.在上面的例子中,它是单向的 oneToMany,它需要一个连接表。

If you save your entity like this enter code here如果您像这样保存实体,请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.这将在连接表中保存关系映射。

Case 2 :- Now if you add the following in the B entity class it will create a foreign-key column to A table.案例 2 :- 现在,如果您在 B 实体类中添加以下内容,它将为 A 表创建一个外键列。 This will be again a unidirection ManyToOne mapping.这将再次是一个单向 ManyToOne 映射。

enter code here


  @ManyToOne()
    A a;

If you the following如果你以下

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);

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.这不会将关系保存在连接表中,而是会使用名为 A_ID 的表 B 列中存在的外键。

Case 3 :- Bidirectional oneToMany案例 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;
    }
}

The above entity mapping is bi-directional oneToMany and doesn't uses the join-table.上面的实体映射是双向的oneToMany,不使用连接表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM