在JPA中,将多对一作为主键会引发引用完整性约束冲突

在JPA中,将多对一作为主键会引发引用完整性约束冲突,jpa,foreign-keys,jpa-2.0,primary-key,many-to-one,Jpa,Foreign Keys,Jpa 2.0,Primary Key,Many To One,我定义了以下实体: @Entity public class Child implements Serializable { @Id @ManyToOne(cascade = CascadeType.ALL) public Parent parent; @Id public int id; } @Entity public class Parent { @Id public int id; } 当我尝试使用以下代码持久化子级时: Parent p

我定义了以下实体:

@Entity
public class Child implements Serializable
{

   @Id
   @ManyToOne(cascade = CascadeType.ALL)
   public Parent parent;

   @Id
   public int id;
}

@Entity
public class Parent
{
   @Id
   public int id;
}
当我尝试使用以下代码持久化子级时:

Parent p = new Parent();
p.id = 1;

Child c1 = new Child();
c1.id = 1;
c1.parent = p;

em.persist(c1);
Hibernate引发“引用完整性约束冲突”错误:

Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK3E104FC802AAC0A: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (1)"; SQL statement:
insert into Child (parent_id, id) values (?, ?) [23506-171]
我相信这是因为它先插入子对象,然后插入父对象,而我希望它先插入父对象。你知道我如何改变插入顺序,或者如何用其他方法解决这个问题吗

更新:请注意,此方法不符合JPA,但使用了Hibernate规范(请参阅中的5.1.2.1.复合标识符部分)


更新:我只需要将子c1持久化,并自动将持久化级联到父p(此更新是对下面@Alf答案的反应)。

我认为您的观点是正确的


你首先需要坚持孩子,然后是父母。

我认为你的观点是正确的

em.persist(p);
em.persist(c1);
您首先需要持久化子对象,然后再持久化父对象

em.persist(p);
em.persist(c1);
更新

我认为问题在于您的代码不符合JPA。尝试使用embeddedId,它对我有效

@Embeddable
public class ChildPK implements Serializable {
    private int parentId;

    private int childId;

    // getters and setters
}

@Entity
public class Child implements Serializable {
    @EmbeddedId
    public ChildPK id = new ChildPK();

    @MapsId( "parentId" )
    @ManyToOne
    public Parent parent;

}


    Parent p = new Parent();
    p.id = 1;

    Child c1 = new Child();
    c1.id.setChildId( 1 );

    c1.parent = p;

    em.persist( c1 );
我认为它也适用于
@IdClass
,但我从未使用过它

更新

我认为问题在于您的代码不符合JPA。尝试使用embeddedId,它对我有效

@Embeddable
public class ChildPK implements Serializable {
    private int parentId;

    private int childId;

    // getters and setters
}

@Entity
public class Child implements Serializable {
    @EmbeddedId
    public ChildPK id = new ChildPK();

    @MapsId( "parentId" )
    @ManyToOne
    public Parent parent;

}


    Parent p = new Parent();
    p.id = 1;

    Child c1 = new Child();
    c1.id.setChildId( 1 );

    c1.parent = p;

    em.persist( c1 );
我想它也适用于
@IdClass
,但我从未使用过它。

巴里

Java中的多同一关系是源对象具有一个引用另一个目标对象的属性,并且(如果)该目标对象与源对象具有反向关系,则它将是一个单同一关系

JPA还定义了一个OneToOne关系,它与多个oneone关系相似,只是反向关系(如果定义)是OneToOne关系

JPA中OneToOne和ManyToOne关系的主要区别在于,ManyToOne始终包含一个从源对象表到目标对象表的外键,其中作为OneToOne关系,外键可能位于源对象表或目标对象表中

您可以看到下面的示例

@Entity
public class Student {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="DEPT_ID")
private Department department;

 //getter and setter
}

@Entity
public class Department {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
 //getter and setter

}


Student student = new Student();
student.setName("prateek");
em.persist(student);


Department dept = new Department();
dept.setName("MCA KIIT");
student.setDepartment(dept);
em.flush();
巴里

Java中的多同一关系是源对象具有一个引用另一个目标对象的属性,并且(如果)该目标对象与源对象具有反向关系,则它将是一个单同一关系

JPA还定义了一个OneToOne关系,它与多个oneone关系相似,只是反向关系(如果定义)是OneToOne关系

JPA中OneToOne和ManyToOne关系的主要区别在于,ManyToOne始终包含一个从源对象表到目标对象表的外键,其中作为OneToOne关系,外键可能位于源对象表或目标对象表中

您可以看到下面的示例

@Entity
public class Student {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="DEPT_ID")
private Department department;

 //getter and setter
}

@Entity
public class Department {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
 //getter and setter

}


Student student = new Student();
student.setName("prateek");
em.persist(student);


Department dept = new Department();
dept.setName("MCA KIIT");
student.setDepartment(dept);
em.flush();

我想这是一个更简单的解决方案:

@Entity
public class Child implements Serializable {
    @Id
    @JoinColumn(name = "id")
    private String id;

    @ManyToOne
    @PrimaryKeyJoinColumn
    private Parent parent;

    private String otherMember;    
}

我想这是一个更简单的解决方案:

@Entity
public class Child implements Serializable {
    @Id
    @JoinColumn(name = "id")
    private String id;

    @ManyToOne
    @PrimaryKeyJoinColumn
    private Parent parent;

    private String otherMember;    
}

不,我的观点是它应该先插入父对象,然后插入子对象。但是我如何做到这一点呢?不,我的观点是它应该先插入父对象,然后插入子对象。但我如何做到这一点呢?你完全正确:这解决了问题。然而,我只想持久化c1,并以某种方式将持久化级联到p。有什么想法吗?谢谢你的回答。这对我也有用。我希望我的模型尽可能简单(没有JPA的东西),但在这个场景中,我不相信(现在)存在这样的解决方案。太糟糕了,谢谢你的帮助。你完全正确:这解决了问题。然而,我只想持久化c1,并以某种方式将持久化级联到p。有什么想法吗?谢谢你的回答。这对我也有用。我希望我的模型尽可能简单(没有JPA的东西),但在这个场景中,我不相信(现在)存在这样的解决方案。太糟糕了,谢谢你的帮助。