简体   繁体   English

JPA hibernate中One To One关系中的外键约束

[英]foreign key constraint in One To One relationship in JPA hibernate

I have two entities A and B with one-to-one relationship. 我有两个实体AB ,一对一的关系。 When I want to insert them into DB, I get the following error: 当我想将它们插入数据库时​​,我收到以下错误:

Cannot add or update a child row: a foreign key constraint fails ( mydb . a , CONSTRAINT FK_77pkrkrin5nqsx16b6nw6k9r7 FOREIGN KEY ( id ) REFERENCES b ( b_id )) 不能添加或更新子行,外键约束失败( mydba ,约束FK_77pkrkrin5nqsx16b6nw6k9r7外键( id )参考bb_id ))

@JsonInclude(JsonInclude.Include.NON_NULL)     
@JsonIgnoreProperties(ignoreUnknown = true, value={"hibernateLazyInitializer", "handler"})
@Generated("org.jsonschema2pojo")
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
public class A {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @JsonIgnore
  private Integer id;

  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
  @PrimaryKeyJoinColumn(referencedColumnName="AId")
  @JsonIgnore
  private B b;

}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true, value = {"hibernateLazyInitializer", "handler"})
@Generated("org.jsonschema2pojo")
@Entity
public class B {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int bId;

  @OneToOne()
  @JsonIgnore
  private A a;

}

The insert operation will work perfectly if I remove the optional=false . 如果我删除optional=false ,插入操作将完美地工作。 I checked the objects before inserting them into DB and I make sure that A contains B and B contains A . 在将对象插入DB之前检查了对象,并确保A包含BB包含A

The SQL scripts for A and B creation are: AB创建的SQL脚本是:

Hibernate: create table b (b_id integer not null auto_increment, string_results longtext, a_id integer, primary key (b_id)) Hibernate:创建表b(b_id整数不为null auto_increment,string_results longtext,a_id整数,主键(b_id))

Hibernate: create table a (id integer not null auto_increment, primary key (id)) Hibernate:创建表a(id整数不为null auto_increment,主键(id))

Hibernate: alter table b add constraint FK_o3oen721etlltdc7ls82524nh foreign key (detail_id) references a (id) Hibernate:alter table b添加约束FK_o3oen721etlltdc7ls82524nh外键(detail_id)引用一个(id)

Hibernate: alter table a add constraint FK_77pkrkrin5nqsx16b6nw6k9r7 foreign key (id) references b (b_id) Hibernate:alter table a add constraint FK_77pkrkrin5nqsx16b6nw6k9r7 foreign key(id)references b(b_id)

When I see the following sentence: 当我看到以下句子时:

I checked the objects before inserting them into DB and I make sure that A contains B and B contains A. 我在将对象插入DB之前检查了对象,并确保A包含B和B包含A.

I guess that you want to create a bidirectional one-to-one relationship. 我想你想创建一个双向的一对一关系。 If so, your current mapping does not work as expected. 如果是这样,您当前的映射无法按预期工作。 Let us see what the JPA 2.0 spec (download link) states about this to understand the matter: 让我们看看JPA 2.0规范 (下载链接)对此有何了解:

Relationships may be bidirectional or unidirectional. 关系可以是双向的或单向的。 A bidirectional relationship has both an owning side and an inverse (non-owning) side. 双向关系具有拥有方和反向(非拥有方)。 A unidirectional relationship has only an owning side. 单向关系只有一个拥有方。 The owning side of a relationship determines the updates to the relationship in the database, as described in section 3.2.4. 关系的拥有方确定数据库中关系的更新,如3.2.4节所述。

The following rules apply to bidirectional relationships: 以下规则适用于双向关系:

• The inverse side of a bidirectional relationship must refer to its owning side by use of the mappedBy element of the OneToOne, OneToMany, or ManyToMany annotation. •双向关系的反面必须通过使用OneToOne,OneToMany或ManyToMany批注的mappedBy元素来引用其拥有方。 The mappedBy element designates the property or field in the entity that is the owner of the relationship. mappedBy元素指定作为关系所有者的实体中的属性或字段。

•The many side of one-to-many / many-to-one bidirectional relationships must be the owning side, hence the mappedBy element cannot be specified on the ManyToOne annotation. •一对多/多对一双向关系的多方必须是拥有方,因此无法在ManyToOne批注上指定mappedBy元素。

• For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key. •对于一对一双向关系,拥有方对应于包含相应外键的一侧。

• For many-to-many bidirectional relationships either side may be the owning side. •对于多对多双向关系,任何一方都可能是拥有方。

So, according to the specification in a bidirectional one-to-one relationship one of the entities must be made the owning side and the other one the inverse side. 因此,根据规范,双向一对一关系中的一个实体必须成为拥有方,而另一个实体必须是反方。 Let assume entity A is the owning side the following mapping should work: 假设实体A是拥有方,以下映射应该起作用:

@Entity
public class A {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer id;

   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
   @JoinColumn(name="b_id", referencedColumnName="ID")
   private B b;

}

@Entity
public class B {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @OneToOne(mappedBy = "b")
    private A a;

}

In order to make the above mapping work either the physical tables must be generated automatically or if you want to create the tables yourself, the corresponding SQL should look the following: 为了使上述映射工作或者必须自动生成物理表,或者如果您想自己创建表,相应的SQL应该如下所示:

create table a (id integer not null auto_increment,
                b_id integer not null,
                primary key (id),
                foreign key b_id references b (id));

create table b (id integer not null auto_increment, 
                string_results longtext, 
                primary key (id));

NOTE: 注意:

  1. I removed the JSON-specific annotation to make the code shorter (I don't have any knowledge about them) 我删除了特定于JSON的注释以使代码更短(我对它们没有任何了解)

  2. If you want to make entity B the owning side, you have to adjust the relationship mapping accordingly. 如果要将实体B作为拥有方,则必须相应地调整关系映射。

  3. The @JoinColumn annotation is always on the owning side. @JoinColumn注释总是在自己的方面。

  4. Due to lack of time I haven't tested the code. 由于时间不够,我还没有测试过代码。 If you find any bug (especially the MySQL syntax) just leave me a comment. 如果您发现任何错误(尤其是MySQL语法),请给我留言。

From the hibernate docs: 来自hibernate的文档:

(Optional) Whether the association is optional. (可选)关联是否可选。 If set to false then a non-null relationship must always exist. 如果设置为false,则必须始终存在非空关系。

Right at the time of creation of B, the b_id is not available, it is created when the flush happens to database. 在创建B时,b_id不可用,它是在数据库发生刷新时创建的。

Since A has a foreign key relation on B(b_id), B needs to be created along with its id before you can insert A or mark this foreign relation as optional. 由于A在B(b_id)上具有外键关系,因此在插入A或将此外键关系标记为可选之前,需要创建B及其id。

Create B and flush it to database, then create A. B has A is not required as its A who defines a foreign key to B and not vice-versa, B's reference to A is only reflexive, two-way foreign key will create cyclic reference issue. 创建B并将其刷新到数据库,然后创建A. B不需要A作为其A定义B的外键而不反之亦然,B对A的引用只是反身,双向外键将创建循环参考问题。

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

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