【问题标题】:JPA - Cascade persist on one to one relationshipJPA - 级联坚持一对一的关系
【发布时间】:2015-09-24 10:50:22
【问题描述】:

我有一个双向的一对一关系,我希望其中一个实体的 ID 也是另一个实体的 ID。

我的代码是这样的:

@Entity
public class UserProfile extends AbstractEntity{
     @OneToOne(mappedBy="user",cascade = CascadeType.ALL)
     private UserPreferences preferences;

     //...
}

另一个实体:

@Entity
public class UserPreferences implements Serializable{
  @Id
  @Column(name="USER_ID")
  private String userId;  // I want USER_ID act as both primary key and foreign key

  @OneToOne
  @PrimaryKeyJoinColumn(name="USER_ID")
  UserProfile user;

  // ...
}

但是当我像这样持久化 UserProfile 时:

UserPreferences pref = new UserPereferences();
pref.setUser(user);
user.setPreferences(pref);
em.persist(user);

它给了我一个错误,说 UserPreferences' Id 不能为空 似乎 jpa 不明白它应该使用 UserProfile Id 作为 UserPreferences Id。

错误:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'USER_ID' cannot be null
Error Code: 1048
Call: INSERT INTO USERPREFERENCES (USER_ID) VALUES (?)

我的代码有问题吗? jpa可以解决这个问题吗?还是我应该单独保留它们?

提前致谢

【问题讨论】:

  • 你在使用休眠吗?你是用它生成 DDL 吗?
  • 我正在使用 eclipselink,是的,我正在生成 ddl,我删除了 userId 并向用户添加了 Id 注释并且它起作用了(正如隐藏建议的那样)我没有像欧文所说的那样尝试 MapsId,但是我相信这也有效

标签: java jpa primary-key cascade one-to-one


【解决方案1】:

使用@MapsId 而不是@PrimaryKeyJoinColumn

@Entity
public class UserPreferences implements Serializable{
  @Id
  @Column(name="USER_ID")
  private String userId;  // I want USER_ID act as both primary key and foreign key

  @MapsId
  @OneToOne
  //@PrimaryKeyJoinColumn(name="USER_ID")
  UserProfile user;

  // ...
}

这将在 DDL 生成期间创建外键定义。

CREATE TABLE USERPREFERENCE (USER_ID VARCHAR(255) NOT NULL, PRIMARY KEY (USER_ID))
CREATE TABLE USERPROFILE (ID VARCHAR(255) NOT NULL, PRIMARY KEY (ID))
ALTER TABLE SESSION ADD CONSTRAINT FK_SESSION_USER_ID FOREIGN KEY (USER_ID) REFERENCES USER (ID)
ALTER TABLE USERPREFERENCE ADD CONSTRAINT FK_USERPREFERENCE_USER_ID FOREIGN KEY (USER_ID) REFERENCES USERPROFILE (ID)

【讨论】:

    【解决方案2】:

    你不要这样做

    @Id
    @Column(name="USER_ID")
    private String userId;  // I want USER_ID act as both primary key and foreign key
    
    @OneToOne
    @PrimaryKeyJoinColumn(name="USER_ID")
    UserProfile user;
    

    因为你使用了两次引用,所以只需要使用一次

    @OneToOne
    @Id
    @Column(name="USER_ID")
    UserProfile user;
    

    例如这样

    【讨论】:

      【解决方案3】:

      注解本身并不足以真正对相关表进行级联操作。您还应该在 FK UserPreferences -> UserProfile 上找到“ON XXX CASCADE”。

      如果您使用 JPA 创建 DDL,您应该在 UserPreferences 表中阅读它。如果 DB 已经创建,您应该删除约束,然后手动添加 CASCADE,如下所示:

       alter table UserPreferences  drop constraint OldConstraintName;
       alter table UserPreferences  add constraint FK_ABABA foreign key (USERID) references UserProfile(USERID) on delete/update/etc.. cascade
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-13
        • 2013-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        相关资源
        最近更新 更多