JPA外键不是对象

Posted

技术标签:

【中文标题】JPA外键不是对象【英文标题】:JPA foreign key NOT AS OBJECT 【发布时间】:2018-02-19 01:51:36 【问题描述】:

我在 mysql 中有两个简单的表

User ---(one-to-many)--- Expense

我正在使用 Spring JPA 来生成这两个实体。费用有 'user_id' 外键字段,它引用用户表中的 'id' 字段。

我在请求中使用 JSON 来填充表格

User
"id":1, "username":"user"

Expense

 "id":1, 
 "user_id":1,        <--- this value is not null in MySQL
 "expense":"expense"

调用 API 时,我已经有了 user_id 值,我不想传递整个对象。

有没有办法告诉 Spring 这是引用 'User' 表中的 'id' 列的 INTEGER FOREIGN KEY?

我在网上找到的所有示例都只显示了如何通过在 JSON 中传递整个“用户”对象来实现。

我目前的实现:

@Entity
public class User
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private int id;

    private String username; 


@Entity
public class Car
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private int id;

    @ManyToOne
    private User user_id;

    private String expense;

【问题讨论】:

【参考方案1】:

您为什么涉及Car 实体?

对我来说这很简单:

@Entity
@Table(xxxx)
public class Expense implements Serializable 
      @ManyToOne
      @JoinColumn(name = "user_id")
      private User user;

够了。 JPA 知道它是一个 FK,并将搜索 User 中的 ID 列。

【讨论】:

【参考方案2】:

对于遇到此问题的任何人: 您可以像这样映射 user_id 列:

@Entity
@Data
public class Expense 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", updatable = false, nullable = false)
  private Integer id;

  @Column(name = "user_id", nullable = false)
  private Integer userId;

  @ManyToOne
  @JoinColumn(name = "user_id", insertable = false, updatable = false)
  private User user;

  private String expense;

如果您只是曾经要像这样使用 user_id 来节省开支:

@Test
void saveExpense_withUserId_expenseSaved() 
    Expense expense = new Expense();
    expense.setUserId(1);

    assertTrue(expenseRepository.save(expense).getId() != null);

要非常小心!如果您尝试通过设置用户对象来保存费用,这将导致 user_id 为空

@Test
void saveExpense_withUser_throwsNullUserId() 
    User testUser = userRepository.findById(1).orElseThrow();

    Expense expense = new Expense();
    expense.setUser(testUser);

    assertThrows(DataIntegrityViolationException.class, () -> expenseRepository.save(expense));

一种更简洁的方法是仅映射关系并在持久化引用时获取对 User 对象的引用:

@Entity
public class Expense 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", updatable = false, nullable = false)
  private Integer id;

  @ManyToOne
  @JoinColumn(name = "user_id", nullable = false)
  private User user;

  private String expense;

@Test
void saveExpense_withUserReference_expenseSaved() 
    Expense expense = new Expense();
    expense.setUser(userRepository.getById(1));
    
    assertTrue(expenseRepository.save(expense).getId() != null);

您使用getById 获得的引用不会生成 SELECT 查询,因此与 findById 不同,它非常有效。注意:您可以通过使用 @ 切换提交来比较这两个代码987654321@

【讨论】:

【参考方案3】:

您不应在请求中传输 JPA 实体。

为您要执行的功能创建具有必要 ID 的 POJOS,并在服务层中映射 Java 实体。

例如,对于查询,您只需实例化实体并设置 ID,如果您需要更多字段,您可以通过 id 执行 find() 并通过直接访问对象获取其余属性

【讨论】:

以上是关于JPA外键不是对象的主要内容,如果未能解决你的问题,请参考以下文章

使用带有外键约束的 JPA 删除对象

JPA JPQL - 如果不使用子对象(没有主键/外键关系)并且可以删除,则返回的查询

无法检索记录使用jpa库外键时为空

带有没有外键的数据库的 Spring JPA

如何使用主键作为JPA和Hibernate的外键引用?

JPA @SecondaryTable 外键违规