I'm working on adding a feature to an already developed spring boot web application. The primary entity that has child entities is a Record. It has a few columns/variables that I want to now be in its own, separate entity (CustomerOrder) and exist in a one-to-one relationship with the Record. To summarize:
Record {
-thing 1
-thing 2
-thing 3
}
is now becoming:
CustomerOrder {
-thing 1
-thing 2
-thing 3
}
Record { CustomerOrder }
I'm having some issues with what I've produced. Here is the CustomerOrder model's relevant relationship data:
@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;
}
And then here is the Record model's relevant data:
@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;
}
My issue exists when I try to POST a record, when a user tries creating one in the ui. Here is the POST method for a record:
@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);
}
The error I receive is the following:
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
This makes sense to me at least, since I'm trying to save the CustomerOrder object that depends on a Record object, which has yet to have been persisted. So, how do I go about changing up the order and/or creating and persisting a Record object so that I can then save the CustomerOrder object to it?
Also, I am using mysql and here is the migration script that I already have. Must I add something here for the customer_orders table?
-- 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');
Here is the mysql script for the Records table and CustomerOrders table:
-- -----------------------------------------------------
-- 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;