JPA外键不作为对象

14

我在MySQL中有两个简单的表格

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

我正在使用Spring JPA生成这两个实体。Expense有一个'user_id'外键字段,它引用了User表中的'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中传递整个"User"对象来实现。

我的当前实现:

@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;
}
3个回答

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));
}

更加简洁的方法是只映射关系,在持久化引用时获取对用户对象的引用:
@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
注意:您可以通过切换提交与this code来比较这两个代码。

0

为什么要涉及Car实体?

对我来说,这很简单:

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

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


0

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

创建带有所需功能ID的POJO,并在服务层中映射Java实体。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接