OneToOne PrimaryKeyJoinColumn Cascade

时间:2015-02-10 16:01:00

标签: hibernate jpa eclipselink jpa-2.0

我正在努力使Eclipselink级联持久的关系:

@Entity
class Notification {
    @Id
    @UuidGenerator(name="UUID_GEN")
    @GeneratedValue(generator="UUID_GEN")
    @Column(name = "NOTIFICATION_ID")
    private UUID id;


    @OneToOne(cascade = ALL, fetch = FetchType.EAGER)
    @JoinFetch(JoinFetchType.INNER)
    @PrimaryKeyJoinColumn(name="NOTIFICATION_ID", referencedColumnName="NOTIFICATION_ID")
    private Notificator notificator;

   ...
}

@Entity
class Notificator {

    @Id
    @Column(name="NOTIFICATION_ID")
    private UUID id;

    ...
}

因此,当我试图保留Notification对象时,Eclipselink无法保留封闭的Notificator对象,因为未设置Notificator.id,因此发生了约束失败。

在第二次尝试中,我尝试使用@MapId注释:

@Entity
class Notification {
    @Id
    @UuidGenerator(name="UUID_GEN")
    @GeneratedValue(generator="UUID_GEN")
    @Column(name = "NOTIFICATION_ID")
    private UUID id;


    @OneToOne
    @MapsId
    private Notificator notificator;

   ...
}

@Entity
class Notificator {

    @Id
    @Column(name="NOTIFICATION_ID")
    private UUID id;

    @OneToOne
    PrimaryKeyJoinColumn(name="NOTIFICATION_ID", referencedColumnName="NOTIFICATION_ID")
    private Notification notification; // didn't need to have it here, but fine.
    ...
}

这样,我甚至无法携带EntityManager。它抛出了这个错误:

  

异常说明:必须为。定义非只读映射   序号字段。

有没有办法让这个级联工作,所以我不需要分别保留这两个实体?我试图避免这种情况,因为有一些其他实体共享这个相同的ID,所以它将是一种肮脏的工作。

谢谢

1 个答案:

答案 0 :(得分:1)

首次尝试时,您在尝试用作外键的字段上有序列注释,没有任何设置Notificator.id字段。如果您希望这一点起作用,您可以创建一个从Notificator到Notification的映射,以便它的ID为#&字段用作外键。

不幸的是,您在第二次尝试时也错误地使用了@PrimaryKeyJoinColumn注释。 @PrimaryKeyJoinColumn用于指定映射中指定的数据库字段由标记为@Id的字段控制和设置,实质上使映射可插入/可更新= false。

为了匹配你想要的结构,你应该尝试:

@Entity
class Notification {
    @Id
    @UuidGenerator(name="UUID_GEN")
    @GeneratedValue(generator="UUID_GEN")
    @Column(name = "NOTIFICATION_ID")
    private UUID id;


    @OneToOne(mappedby="notification", cascade = ALL, fetch = FetchType.EAGER)
    @JoinFetch(JoinFetchType.INNER)
    private Notificator notificator;

   ...
}

@Entity
class Notificator {

    @Id
    @Column(name="NOTIFICATION_ID")
    private UUID id;

    @OneToOne
    @JoinColumn(name="NOTIFICATION_ID", referencedColumnName="NOTIFICATION_ID", insertable=false, updatable=false)
    private Notification notification; 
    ...
}

这并不完全符合您的要求,因为上面的示例要求您在引用的Notification.id中的值可用后自己设置Notificator.id值(post persist / flush)。

如果您使用的是JPA 2.0,则可以使用Notificator类中的@MapsId而不是指定连接列,以便在持久保存对象图时让JPA在托管实体中自动设置Notificator.id字段值: / p>

@Entity
class Notificator {

    @Id
    private UUID id;

    @OneToOne
    @MapsId
    @JoinColumn(name="NOTIFICATION_ID", referencedColumnName="NOTIFICATION_ID")
    private Notification notification; 
    ...
}

正如您所指出的,您并不需要模型中的Notificator.notification和Notificator.id值,但如果您想要Notificator的值,则至少需要Notificator.notification。&#34 ; NOTIFICATION_ID"字段来自通知。 JPA 2.0允许您删除Notificator.id并使用Notificator.notification关系作为实体ID使用:

@Entity
class Notificator {

    @Id
    @OneToOne
    @JoinColumn(name="NOTIFICATION_ID", referencedColumnName="NOTIFICATION_ID")
    private Notification notification; 
    ...
}

这允许您仍然使用UUID值进行身份查找。 FetchJoins等可以确保始终提取关系,但是缺点是希望使用ID值的JPQL需要使用notificator.notification.id来访问它。