Spring JPA:一对一关系中的共享 PK 问题
Spring JPA: Issue with shared PK in one-to-one relationship
我正在尝试创建一对一的共享 PK 关系,但在尝试了很多事情后我感到很困惑...
我会尽量提供所有可能的信息:
我使用的技术:
- Spring 启动 2.1.5
- Spring JPA
- 飞行路线
数据源配置:
spring.datasource.url = jdbc:mysql://localhost:3306/customers?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username = admin
spring.datasource.password = root
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql = true
数据库模型:
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "customer", schema = "customers")
public class Customer {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "customer_id", columnDefinition = "BINARY(16)")
private UUID customerId;
@OneToOne(mappedBy = "customer", cascade = CascadeType.ALL)
private Address address;
}
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "address", schema = "customers")
public class Address {
@Id
@Column(name = "address_id", columnDefinition = "BINARY(16)")
private UUID addressId;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Customer customer;
}
Flyway迁移文件:
CREATE SCHEMA IF NOT EXISTS CUSTOMERS;
CREATE TABLE CUSTOMERS.CUSTOMER
(
customer_id BINARY(16) NOT NULL PRIMARY KEY,
) ENGINE = InnoDB;
CREATE TABLE CUSTOMERS.ADDRESS
(
address_id BINARY(16) NOT NULL PRIMARY KEY,
) ENGINE = InnoDB;
ALTER table CUSTOMERS.ADDRESS
ADD CONSTRAINT fk_customer_address
FOREIGN KEY (address_id)
REFERENCES CUSTOMERS.CUSTOMER (customer_id);
集成测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerRepositoryIntegrationTest {
@Autowired
private CustomerRepository cut;
@Test
public void testSaveAndDeleteCustomer() {
Address address = new Address();
Customer customer = new Customer();
customer.setAddress(address);
cut.save(customer);
Customer retrievedCustomer = cut.findAll().get(0);
assertEquals(customer, retrievedCustomer);
}
}
错误:
ERROR] testSaveAndDeleteCustomer(com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest) Time elapsed: 0.034 s <<< ERROR!
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]
at com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest.testSaveAndDeleteCustomer(CustomerRepositoryIntegrationTest.java:47)
Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]
at com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest.testSaveAndDeleteCustomer(CustomerRepositoryIntegrationTest.java:47)
提前感谢您的帮助。
干杯!
您不了解双向映射的工作原理,因此您需要仔细考虑一下。代码
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Customer customer;
in Address
使映射成为单向的。通常为了保存它,您需要设置 customer
字段并保存它。
address.setCustomer(customer);
addressRepo.save(address);
但是您已经定义了双向映射并提供了级联注释。
@OneToOne(mappedBy = "customer", cascade = CascadeType.ALL)
private Address address;
级联注释使您不必执行两个持久化操作(在您的代码中),但这并不意味着您不必在地址中设置客户字段。此外,正如您所注意到的,为了使级联操作起作用,您需要设置客户的地址字段。
customer.setAddress(address);
因此,为了使代码正常工作,您需要更改它以设置客户地址。
Address address = new Address();
Customer customer = new Customer();
customer.setAddress(address);
address.setCustomer(customer);
customerRepo.save(customer);
使用双向映射,您必须管理关系的两边,或者以单向方式使用它来持久化,以双向方式使用它来检索。如果您添加级联注释,那么您还必须管理关系的双方以保持持久性。
我正在尝试创建一对一的共享 PK 关系,但在尝试了很多事情后我感到很困惑...
我会尽量提供所有可能的信息:
我使用的技术:
- Spring 启动 2.1.5
- Spring JPA
- 飞行路线
数据源配置:
spring.datasource.url = jdbc:mysql://localhost:3306/customers?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username = admin
spring.datasource.password = root
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql = true
数据库模型:
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "customer", schema = "customers")
public class Customer {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "customer_id", columnDefinition = "BINARY(16)")
private UUID customerId;
@OneToOne(mappedBy = "customer", cascade = CascadeType.ALL)
private Address address;
}
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "address", schema = "customers")
public class Address {
@Id
@Column(name = "address_id", columnDefinition = "BINARY(16)")
private UUID addressId;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Customer customer;
}
Flyway迁移文件:
CREATE SCHEMA IF NOT EXISTS CUSTOMERS;
CREATE TABLE CUSTOMERS.CUSTOMER
(
customer_id BINARY(16) NOT NULL PRIMARY KEY,
) ENGINE = InnoDB;
CREATE TABLE CUSTOMERS.ADDRESS
(
address_id BINARY(16) NOT NULL PRIMARY KEY,
) ENGINE = InnoDB;
ALTER table CUSTOMERS.ADDRESS
ADD CONSTRAINT fk_customer_address
FOREIGN KEY (address_id)
REFERENCES CUSTOMERS.CUSTOMER (customer_id);
集成测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerRepositoryIntegrationTest {
@Autowired
private CustomerRepository cut;
@Test
public void testSaveAndDeleteCustomer() {
Address address = new Address();
Customer customer = new Customer();
customer.setAddress(address);
cut.save(customer);
Customer retrievedCustomer = cut.findAll().get(0);
assertEquals(customer, retrievedCustomer);
}
}
错误:
ERROR] testSaveAndDeleteCustomer(com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest) Time elapsed: 0.034 s <<< ERROR!
org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]
at com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest.testSaveAndDeleteCustomer(CustomerRepositoryIntegrationTest.java:47)
Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.foxhound.customers.models.Address.customer]
at com.foxhound.customers.repositories.CustomerRepositoryIntegrationTest.testSaveAndDeleteCustomer(CustomerRepositoryIntegrationTest.java:47)
提前感谢您的帮助。
干杯!
您不了解双向映射的工作原理,因此您需要仔细考虑一下。代码
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Customer customer;
in Address
使映射成为单向的。通常为了保存它,您需要设置 customer
字段并保存它。
address.setCustomer(customer);
addressRepo.save(address);
但是您已经定义了双向映射并提供了级联注释。
@OneToOne(mappedBy = "customer", cascade = CascadeType.ALL)
private Address address;
级联注释使您不必执行两个持久化操作(在您的代码中),但这并不意味着您不必在地址中设置客户字段。此外,正如您所注意到的,为了使级联操作起作用,您需要设置客户的地址字段。
customer.setAddress(address);
因此,为了使代码正常工作,您需要更改它以设置客户地址。
Address address = new Address();
Customer customer = new Customer();
customer.setAddress(address);
address.setCustomer(customer);
customerRepo.save(customer);
使用双向映射,您必须管理关系的两边,或者以单向方式使用它来持久化,以双向方式使用它来检索。如果您添加级联注释,那么您还必须管理关系的双方以保持持久性。