使用共享主键的JPA / Hibernate单向一对一映射 [英] JPA / Hibernate unidirectional one-to-one mapping with shared primary key

查看:129
本文介绍了使用共享主键的JPA / Hibernate单向一对一映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我非常难以获得单向的一对一关系来处理JPA(Provider:Hibernate)。在我看来,这不应该太麻烦,但显然JPA / Hibernate不同意这一点; - )

问题是我必须映射一个遗留模式,我无法更改,并且此架构在两个实体之间使用共享主键,同时它们是一个实体的外键。



我创建了一个简单的TestCase:



DB如下所示:

  CREATE TABLE PARENT(PARENT_ID Number primary key,Message varchar2(50)); 

CREATE TABLE CHILD(CHILD_ID数字主键,消息varchar2(50),
CONSTRAINT FK_PARENT_ID FOREIGN KEY(CHILD_ID)REFERENCES PARENT(PARENT_ID));

CREATE SEQUENCE SEQ_PK_PARENT START WITH 1 INCREMENT BY 1 ORDER;

父母(=一对一的拥有方)如下所示:



pre $ @Entity
@Table(name =PARENT)
public class Parent implements java.io.Serializable {
私人长期parentId;
私人字符串消息;
私人小孩;

@Id
@Column(name =PARENT_ID,unique = true,nullable = false,precision = 22,scale = 0)
@SequenceGenerator(name =pk_sequence ,sequenceName =SEQ_PK_PARENT)
@GeneratedValue(generator =pk_sequence,strategy = GenerationType.SEQUENCE)
public Long getParentId(){
return this.parentId;
}

public void setParentId(Long parentId){
this.parentId = parentId;


@Column(name =MESSAGE,length = 50)
public String getMessage(){
return this.message;
}

public void setMessage(String message){
this.message = message;
}

@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn(name =PARENT_ID,referencedColumnName =CHILD_ID)
public Child getTestOneToOneChild() {
返回this.child;
}

public void setTestOneToOneChild(Child child){
this.child = child;


$ / code $ / pre
$ b $ p


  @Entity 
@Table(name =TEST_ONE_TO_ONE_CHILD,schema =EXTUSER)
public class Child实现java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long childId;

私人字符串消息;
$ b $ public Child(){
}

public Child(String message){
this.message = message;
}

@Id
@Column(name =CHILD_ID)
public Long getChildId(){
return this.childId;
}

public void setChildId(Long childId){
this.childId = childId;


@Column(name =MESSAGE,length = 50)
public String getMessage(){
return this.message;
}

public void setMessage(String message){
this.message = message;
}
}

我完全看到JPA不知道为孩子分配ID。不过我也尝试过使用Hibernates的外部键生成器也没有成功,因为那个人需要有一个不希望的从父母的父引用。
这个问题对我来说并不罕见,所以我在这里错过了什么?有没有解决方案?如果纯JPA不提供解决方案,我也可以使用hibernate扩展。



我对正确行为的期望是:
如果我试图持久父项附带一个孩子:


  1. 从序列中获取ID,将其设置在父项上

  2. 持久父项

  3. 在子女上设置家长ID

  4. 持续子女



<如果我试图坚持一个独立的孩子(例如entityManager.persist(aChild)),我会期待一个RuntimeException。



非常感谢任何帮助!对于您描述的数据库模式,您可以使用 6 / api / javax / persistence / MapsId.htmlrel =nofollow> @ MapsId 注释,以实现映射回父级,如下所示:

  @Entity 
class父母{
@Id
@Column(name =parent_id)
@GeneratedValue
长的parent_id;
}

@Entity
class Child {
@Id
@Column(name =child_id)
Long child_id;

@MapsId
@OneToOne
@JoinColumn(name =child_id)
父母;
}

添加从父到子的映射,您可以使用@PrimaryKeyJoinColumn注释列出,使得完整的双向一对一映射如下所示:

  @Entity 
class父{
@Id
@Column(name =parent_id)
@GeneratedValue
Long parent_id;

@OneToOne
@PrimaryKeyJoinColumn(name =parent_id,referencedColumnName =child_id)
public Child;
}

@Entity
class Child {
@Id
@Column(name =child_id)
Long child_id;

@MapsId
@OneToOne
@JoinColumn(name =child_id)
父母;
}

我使用字段而不是方法访问​​(并删除了与关系无关的任何内容) ,但它将应用于您的getters相同的注释。



另请参阅2.2.3.1 这里是另一个@MapsId的例子。


I'm having a very hard time trying to get a unidirectional one-to-one relationship to work with JPA (Provider: Hibernate). In my opinion this should not be too much of a hassle but apparently JPA / Hibernate disagrees on that ;-)

The problem is that I have to map a legacy schema which I cannot change and that this schema uses a shared primary key between two entities which at the same time is the foreign key for one entity.

I created a simple TestCase:

DB looks as follows:

CREATE TABLE PARENT (PARENT_ID Number primary key, Message varchar2(50));

CREATE TABLE CHILD (CHILD_ID Number primary key, Message varchar2(50),
CONSTRAINT FK_PARENT_ID FOREIGN KEY (CHILD_ID )REFERENCES PARENT (PARENT_ID));

CREATE SEQUENCE SEQ_PK_PARENT START WITH 1 INCREMENT BY 1 ORDER;

The parent(=owning side of one-to-one) looks as follows:

@Entity
@Table(name = "PARENT")
public class Parent implements java.io.Serializable {       
    private Long parentId;
    private String message;
    private Child child;

    @Id
    @Column(name = "PARENT_ID", unique = true, nullable = false, precision = 22, scale = 0)
    @SequenceGenerator(name="pk_sequence", sequenceName="SEQ_PK_PARENT")
    @GeneratedValue(generator="pk_sequence", strategy=GenerationType.SEQUENCE)
    public Long getParentId() {
        return this.parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    @Column(name = "MESSAGE", length = 50)
    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @OneToOne (cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn(name="PARENT_ID", referencedColumnName="CHILD_ID")
    public Child getTestOneToOneChild() {
        return this.child;
    }

    public void setTestOneToOneChild(Child child) {
        this.child = child;
    }
}

The child:

@Entity
@Table(name = "TEST_ONE_TO_ONE_CHILD", schema = "EXTUSER")
public class Child implements java.io.Serializable {    
    private static final long serialVersionUID = 1L;
    private Long childId;       

    private String message;

    public Child() {
    }

    public Child(String message) {
        this.message = message;
    }

    @Id
    @Column(name = "CHILD_ID")    
    public Long getChildId() {
        return this.childId;
    }

    public void setChildId(Long childId) {
        this.childId = childId;
    }

    @Column(name = "MESSAGE", length = 50)
    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

I totally see the problem that JPA does not know how to assign the id for the child. However I also tried using Hibernates "foreign" key Generator with also no success because that one needs to have a back reference to the parent from child which is not desirable. This problem does not seem too uncommon to me, so what am I missing here? Is there a solution at all? I can also use hibernate extensions if pure JPA does not provide a solution.

My expectations for a correct behavior would be: If I try to persist the parent with a child attached:

  1. get ID from sequence, set it on the parent
  2. persist parent
  3. set parent's ID on child
  4. persist child

If I try to persist a "standalone" child (e.g. entityManager.persist(aChild)) I would expect a RuntimeException.

Any help is greatly appreciated!

解决方案

For the db schema you described, you can use @MapsId annotation on the dependent class (your Child class) to achieve the mapping back to the parent, like so:

@Entity
class Parent {
  @Id
  @Column(name = "parent_id")
  @GeneratedValue 
  Long parent_id;
}

@Entity
class Child {
  @Id
  @Column(name = "child_id")
  Long child_id;

  @MapsId 
  @OneToOne
  @JoinColumn(name = "child_id")
  Parent parent;
}

Adding the mapping from parent to child you use the @PrimaryKeyJoinColumn annotation as you had listed, making the complete bi-directional one-to-one mapping look like this:

@Entity
class Parent {
  @Id
  @Column(name = "parent_id")
  @GeneratedValue 
  Long parent_id;

  @OneToOne
  @PrimaryKeyJoinColumn(name="parent_id", referencedColumnName="child_id")
  public Child;
}

@Entity
class Child {
  @Id
  @Column(name = "child_id")
  Long child_id;

  @MapsId 
  @OneToOne
  @JoinColumn(name = "child_id")
  Parent parent;
}

I used field rather than method access (and removed anything extraneous to the relationships), but it would be the same annotations applied to your getters.

Also see the last bit of section 2.2.3.1 here for another example of @MapsId.

这篇关于使用共享主键的JPA / Hibernate单向一对一映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆