【问题标题】:SpringDataJPA save OneToOne relationship through primary/foreign key, object saved orderSpring Data JPA通过主/外键保存一对一关系,对象保存顺序
【发布时间】:2015-04-25 11:27:54
【问题描述】:

我有 USER(id) 和 CONTACT(user_id, first, last) 表。 CONTACT.user_id 是 USER 表的外键。

在 User.java 中:

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

@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Contact contact;

在 Contact.java 中

@Id
@Column(name="USER_ID")
private Integer userId;

@MapsId 
@OneToOne(mappedBy = "contact")
@JoinColumn(name = "USER_ID")
private User user;

我使用 userRepository.saveAndFlush(user) 来保存 USER 对象。由于我在 CONTACT 中使用 USER.ID 作为外键,所以我需要在 CONTACT 之前插入 USER,但 JPA 是先插入 CONTACT,它会将 CONTACT 视为 USER 的成员。所以我在插入 CONTACT 时收到 USER_ID can not be NULL 错误。我应该怎么做才能解决这个插入顺序?还是我应该完全通过共享主键来避免使用 OneToOne 映射?

谢谢!

【问题讨论】:

标签: mysql hibernate jpa eclipselink spring-data-jpa


【解决方案1】:

我有 USER(id) 和 CONTACT(id, first, last) 表。 CONTACT.user_id 是 USER 表的外键

通过发表此声明,我会说这种关系不是与共享主键的一对一关系。如果是这种情况,我希望表结构如下所示。

USER(id)
CONTACT(id, first, last)

作为使用@OneToOne 的替代方法,您可以考虑使用@SecondaryTable,即在两个表中映射用户实体:这似乎更适合模型。

http://en.wikibooks.org/wiki/Java_Persistence/Tables#Multiple_tables

无论如何,如果您想使用@OneToOne,那么下面的 API 文档示例二给出了

假设源和假设的一对一关联示例 目标共享相同的主键值。

http://docs.oracle.com/javaee/6/api/javax/persistence/OneToOne.html

接下来我会说映射应该如下:

public class User{

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

    @OneToOne(mappedBy ="user", cascade =CascadeType.ALL)
    private Contact contact;
}

public class Contact{

    @Id
    private Long id;

    @OneToOne
    @MapsId
    @JoinColumn(name = "user_id")
    private User user;
}

【讨论】:

  • MapsId 告诉 JPA 引用的 Contact 实例的 userId 字段中使用的值应该用于设置 User.id 属性中的值。排序需要放在 Contact.userId 字段上才能工作,否则它将始终为空(除非由应用程序手动设置)
  • 我提出的映射实际上是错误的。我已经在 MySQL 上测试了更新的映射,没有任何问题。
【解决方案2】:

问题似乎是您将 User.contact 关系设置为控制关系 - 您已将 Contact.user 关系标记为 mappedBy 联系人映射以及指定的 joinColumn 是错误的。 Contact.user 关系上的这些设置冲突,因此只能使用一个,并且 mappedBy 本质上表明外键字段由 User.contact 关系控制,强制您看到的插入顺序。

切换映射将为您提供所需的内容:

public class User{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    private Contact contact;
}

public class Contact{
    @Id
    private Integer userId;

    @MapsId 
    @OneToOne()
    @JoinColumn(name = "USER_ID")
    private User user;
}

上述映射指定 USER_ID 是 User.ID 字段的外键,并将此关系用于 User.contact 和 Contact.user 关系。一旦在引用的用户实例中设置了 MapsId,Contact.user 关系也可以为您设置 Contact.userId 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 2015-05-10
    • 2021-09-27
    相关资源
    最近更新 更多