【问题标题】:Field 'record_id' doesn't have a default value - Spring JPA Error字段“record_id”没有默认值 - Spring JPA 错误
【发布时间】:2023-03-08 21:27:01
【问题描述】:

我正在为已经开发的 Spring Boot Web 应用程序添加一项功能。具有子实体的主要实体是记录。它有一些列/变量,我现在希望它们位于它自己的独立实体 (CustomerOrder) 中,并与记录以一对一的关系存在。总结一下:

记录{

-事物 1

-事物2

-第三件事

}

现在变成:

客户订单{

-事物 1

-事物2

-第三件事

}

记录{客户订单}

我对我制作的内容有一些问题。这是 CustomerOrder 模型的相关关系数据:

@Entity
@Table(name="customer_orders")
public class CustomerOrder {

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

    ... other columns

    @OneToOne(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy="customerOrder", fetch = FetchType.EAGER)
    private Record record;


}

然后是Record模型的相关数据:

@Entity
@Table(name="records")
public class Record extends Auditable<String> implements Serializable {

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

    ... other columns

    @OneToOne
    @JoinColumn(name="customer_order_id", nullable = false, unique = true)
    private CustomerOrder customerOrder;
}

当我尝试发布记录时,当用户尝试在 ui 中创建记录时,我的问题存在。这是记录的 POST 方法:

    @PostMapping
    public ResponseEntity<?> saveRecord(@RequestBody Record recordBody, BindingResult result) {
        if(!result.hasErrors()) {
            if(recordBody.getHardwareItems().isEmpty()) {
                record = recordsService.save(recordBody);
            } else {
                // Save the record first, recordId is required on hardwareItems
                // TODO: investigate Spring Hibernate/JPA rules - is there a way to save parent before children to avoid a null recordId
                CustomerOrder customerOrder = recordBody.getCustomerOrder();
                recordBody.setCustomerOrder(new CustomerOrder());
                customerOrder.setRecord(record);
                customerOrder = customerOrdersService.save(customerOrder);
                record = recordsService.save(recordBody);
            }
        } else {
            return new ResponseEntity<>(result.getAllErrors(), HttpStatus.BAD_REQUEST);
        }
        // Return the location of the created resource
        uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{recordId}").buildAndExpand(record.getId()).toUri();
        return new ResponseEntity<>(uri, HttpStatus.CREATED);
    }

我收到的错误如下:

2021-02-19 02:35:50.989  WARN 31765 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1364, SQLState: HY000
2021-02-19 02:35:50.989 ERROR 31765 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper   : Field 'record_id' doesn't have a default value

这至少对我来说是有意义的,因为我正在尝试保存依赖于 Record 对象的 CustomerOrder 对象,该对象尚未被持久化。那么,我该如何更改订单和/或创建和持久化 Record 对象,以便我可以将 CustomerOrder 对象保存到其中?

另外,我正在使用 mysql,这是我已经拥有的迁移脚本。我必须在这里为 customer_orders 表添加一些东西吗?

-- Add a sample user
INSERT IGNORE INTO users (first_name, last_name, email, password, enabled, role)
VALUES ('Sample', 'User', 'sample@email.com', 'sample password', true, 'ROLE_ADMIN');

-- Customer Reference Values
INSERT IGNORE INTO customers (name) VALUES ('value1');
INSERT IGNORE INTO customers (name) VALUES ('value2');
INSERT IGNORE INTO customers (name) VALUES ('value3');
INSERT IGNORE INTO customers (name) VALUES ('value4');
INSERT IGNORE INTO customers (name) VALUES ('value5');
INSERT IGNORE INTO customers (name) VALUES ('value6');
INSERT IGNORE INTO customers (name) VALUES ('value7');
INSERT IGNORE INTO customers (name) VALUES ('value8');

这是 Records 表和 CustomerOrders 表的 mysql 脚本:

-- -----------------------------------------------------
-- Table `myapp`.`records`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `myapp`.`records` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `customer_order_id` BIGINT NOT NULL,
  `record_id` BIGINT NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `UK_7m7wsqy68b7omkufvckoqv2hf` (`customer_order_id` ASC) VISIBLE,
  INDEX `FKta31a9q1llknlo2n0jw741987` (`customer_id` ASC) VISIBLE,
  CONSTRAINT `FK3q3clytyrx7s8edp9ok821j3`
    FOREIGN KEY (`customer_order_id`)
    REFERENCES `myapp`.`customer_orders` (`id`),
  CONSTRAINT `FKta31a9q1llknlo2n0jw741987`
    FOREIGN KEY (`customer_id`)
    REFERENCES `myapp`.`customers` (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 27
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;


-- -----------------------------------------------------
-- Table `myapp`.`customer_orders`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `myapp`.`customer_orders` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `record_id` BIGINT NOT NULL,
  `record_id_test` BIGINT NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `UK_ilew9pg8y4qnyhmjg38k1fev2` (`record_id_test` ASC) VISIBLE,
  INDEX `FK5rpb3u59bblj7h70wjr5mvb01` (`record_id` ASC) VISIBLE,
  CONSTRAINT `FK5rpb3u59bblj7h70wjr5mvb01`
    FOREIGN KEY (`record_id`)
    REFERENCES `myapp`.`records` (`id`),
  CONSTRAINT `FKk7a0g7djyhymr54ehoftkhyfw`
    FOREIGN KEY (`record_id_test`)
    REFERENCES `myapp`.`records` (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci;

【问题讨论】:

  • 可以分享建表脚本吗?似乎您正在尝试拥有一个在表创建期间未定义的自动增量字段。另外您使用的是什么类型的数据库?
  • 我正在使用 mysql,这是一个多人项目,所以我想表的迁移脚本是我对需要添加的内容有点困惑的地方......如果任何事物。但是我也将这些信息添加到了上面的答案中。我也必须为 customer_orders 表添加一些东西吗?
  • 你也可以分享SQL 脚​​本吗?
  • @akortex91 我添加了我认为与这两个表相关的脚本数据。我注意到“record_id_test”,这似乎很可疑,我不确定它来自哪里。
  • 更可疑的是customer_orders.record_id,它不应该存在于mappedBy 属性中。您是自己创建表还是使用休眠?

标签: java spring hibernate spring-data-jpa entity-model


【解决方案1】:

您的架构与您的实体不匹配。您的 customer_orders 表不应有 record_id 列。您指定您的记录表应该有一个列 customer_order_id。您使用注释明确定义:

@JoinColumn(name="customer_order_id", nullable = false, unique = true)

但是,你的注释在另一边

@OneToOne(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy="customerOrder", fetch = FetchType.EAGER)

表示这只是一个使用另一个表中的外键的反向引用。从您的架构中删除该列。 我假设您的数据库架构中但不是您的实体的其他列与您的用例无关,因为您有 cmets 说您的实体有其他字段。但是,外键没有意义,并且与您的实体不匹配。从您的数据库架构中删除该列。

【讨论】:

    【解决方案2】:

    如果我的理解是正确的,那么您将在一对一关系中进行两种映射。所以,customer_order 有一个 record_id 列,record 有一个 customer_order_id 列。这并不理想,hibernate 不自动支持这种类型的映射。如果您考虑一下,如果两列都不可为空,那么您无法保存数据 b/c 您无法同时保存两者。您必须先保存一个。

    如果你想保留它,你必须让其中一个不可为空。然后保存一个,然后另一个,然后使用您现在生成的另一个的 id 重新保存第一个。

    这里hibernate首先尝试保存customer_order,b/c你说customer_order_idrecords表中并且不可为空。这是默认设置。我建议保留它,并删除 customer_orders 表中的另一个 record_id 列。

    更新: 为了澄清,这里是一种解决方案。由于 record_id 和 record_id_test 不可为空,因此在代码中设置它们的值,然后保存。它应该可以工作。

    如果我遗漏了什么,请提供更多信息,例如底层数据库、record_id 列在您的模型中的位置等。

    【讨论】:

    • 谢谢你的回答,但我对你的建议有点困惑。您能否在答案中准确输入要更改的内容以进行澄清?我对在这两个实体中要更改什么以及是否需要在 saveRecord() 方法中做任何事情感到困惑。
    【解决方案3】:

    删除两个record_id 列或为它们提供默认值。它们没有映射到实体中的任何内容,因此 Hibernate 没有将它们包含在插入语句中,这会导致失败,因为它们都配置为 NOT NULL

    我猜他们的目的是以某种方式保存RecordCustomerOrder 之间的引用,但它被映射到customer_order_id

    @JoinColumn(name="customer_order_id", nullable = false, unique = true)
    

    【讨论】:

      【解决方案4】:

      在表创建脚本中,您似乎还在RECORDS 表中包含了一个名为RECORD_ID 的列。它已经有标准的ID 列来存储主键。不确定您是否真的需要那里的RECORD_ID 列。这被标记为 NOT NULL 并且在表创建脚本中没有设置默认值,因此您得到了错误。

      查看表创建脚本中的约束,看起来应该命名为 CUSTOMER_ID 而不是 RECORD_ID

      请将此作为第一步。

      【讨论】:

        【解决方案5】:

        为 customerOrder 变量上方的注释添加 @OneToOne(cascade = CascadeType.PERSIST) 是我基本上必须做的所有事情来解决这个问题。该小组中的另一位开发人员帮助了我。然后,我可以摆脱 POST 方法中对 CustomerOrder 值的所有引用,只需要在 Record 的 PUT 方法中为 CustomerOrder 设置一个设置器。

        【讨论】:

          猜你喜欢
          • 2015-04-23
          • 2021-10-17
          • 1970-01-01
          • 2013-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多