【问题标题】:JPA foreign key NOT AS OBJECTJPA外键不是对象
【发布时间】: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;
}

【问题讨论】:

    标签: spring hibernate jpa


    【解决方案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() 并通过直接访问对象获取其余属性

        【讨论】:

          猜你喜欢
          • 2021-08-24
          • 1970-01-01
          • 2015-02-03
          • 2011-04-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-16
          相关资源
          最近更新 更多