在spring-data-jdbc中使用一对一关系时,如何使相关实体的id(自动递增)被插入?
How to make related entity's id(auto-incremented) to be inserted when using one to one relationship in spring-data-jdbc?
我有两个表,它们是 profile_info 和 user_Info。
数据库 ER 图
Table创作:
CREATE TABLE `user_info` (
`id` int NOT NULL AUTO_INCREMENT,
`userLogin` varchar(20) DEFAULT NULL,
`userPassword` varchar(60) DEFAULT NULL,
`userType` enum('user','administrator') DEFAULT NULL,
`userEmail` varchar(320) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `userEmail` (`userEmail`)
);
CREATE TABLE `profile_info` (
`id` int NOT NULL AUTO_INCREMENT,
`userId` int DEFAULT NULL,
`userRegistrationDate` datetime DEFAULT NULL,
`userFirstName` varchar(25) DEFAULT NULL,
`userSurName` varchar(25) DEFAULT NULL,
`accountBalance` double DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `userUniqueId` (`userId`),
CONSTRAINT `fkUserId` FOREIGN KEY (`userId`) REFERENCES `user_info` (`id`) ON DELETE CASCADE,
CONSTRAINT `chk_accountBalance` CHECK ((`accountBalance` >= 0))
);
所以我有一对一的关系(一个配置文件只与一个用户相关)
这是我的实体:
用户:
@Table("user_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Persistable<Integer> {
@Id
@Column("id")
private Integer id;
@Column("userLogin")
private String userLogin;
@Column("userPassword")
private String userPassword;
@Column("userType")
private String userType;
@Column("userEmail")
private String userEmail;
@Override
public boolean isNew() {
return id==null;
}
}
简介:
@Table("profile_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile implements Persistable<Integer> {
@Id
@Column("id")
private Integer id;
@Column("userRegistrationDate")
private LocalDateTime userRegistrationDate;
@Column("userFirstName")
private String userFirstName;
@Column("userSurName")
private String userSurName;
@Column("accountBalance")
private double accountBalance;
@MappedCollection(idColumn = "id")
private User user;
@Override
public boolean isNew() {
return id==null;
}
}
我使用标准存储库作为 CRUDRepository
用户资料库:
@Repository
public interface UserRepository extends CrudRepository<User,Long> {
}
配置文件存储库:
@Repository
public interface ProfileRepository extends CrudRepository<Profile,Integer> {
}
我有 spring 配置:
@Configuration
@EnableJdbcRepositories("com.example.testrepositories.repository")
public class ApplicationConfig extends AbstractJdbcConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource managerDataSource = new DriverManagerDataSource();
managerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
managerDataSource.setUrl("jdbc:mysql://localhost:3306/testdatabase");
managerDataSource.setUsername("Bruce");
managerDataSource.setPassword("givanchy");
return managerDataSource;
}
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
我测试存储库的主要方法:
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
ProfileRepository repository = context.getBean("profileRepository",ProfileRepository.class);
User user = new User(null,"TestLogin","testPassword","user","eeed");
Profile profile = new Profile(null, LocalDateTime.now(),"fff","sss",250.0,user);
Profile savedProfile = repository.save(profile);
System.out.println(savedProfile.getId());
System.out.println(savedProfile.getUser().getId());
}
输出为:
在这些操作之后我在数据库中有以下内容:
用户信息已按原样插入
但是在配置文件中没有插入 userId,应该这样吗?
编辑
我将根实体从配置文件更改为用户,效果很好
用户实体:
@Table("user_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Persistable<Integer>{
@Id
@Column("id")
private Integer id;
@Column("userLogin")
private String userLogin;
@Column("userPassword")
private String userPassword;
@Column("userType")
private String userType;
@Column("userEmail")
private String userEmail;
@MappedCollection(keyColumn = "id",idColumn = "userId")
private Profile profile;
@Override
public boolean isNew() {
return id==null;
}
}
个人资料实体:
@Table("profile_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile implements Persistable<Integer>{
@Id
@Column("id")
private Integer id;
@Column("userRegistrationDate")
private LocalDateTime userRegistrationDate;
@Column("userFirstName")
private String userFirstName;
@Column("userSurName")
private String userSurName;
@Column("accountBalance")
private double accountBalance;
@Override
public boolean isNew() {
return id==null;
}
}
看来一对一关系的使用是错误的。根据您的 ER 图,每个 User
可以有多个 Profile
行。如果是这种情况并且 Profile
是一个聚合(根),那么 user_info
也是一个聚合根。为两个实体都提供一个存储库也是如此。
因此,我们处理聚合之间的引用,这些引用应该仅由 id 表示,而不是对象引用。这意味着您应该制作 Profile.user
和 Integer
或 AggregateReference<Integer>
并在 User
保存后将其设置为 User.id
的值。
一些其他注意事项:
MappedCollection
与简单引用无关。
当 A
引用 B
时,数据库中的外键方向相反。因此,如果 Profile
和 User
确实存在一对一的关系,那么 User
应该是聚合根。
有关所有这些的更多背景信息,请参阅 https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates
我有两个表,它们是 profile_info 和 user_Info。 数据库 ER 图
Table创作:
CREATE TABLE `user_info` (
`id` int NOT NULL AUTO_INCREMENT,
`userLogin` varchar(20) DEFAULT NULL,
`userPassword` varchar(60) DEFAULT NULL,
`userType` enum('user','administrator') DEFAULT NULL,
`userEmail` varchar(320) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `userEmail` (`userEmail`)
);
CREATE TABLE `profile_info` (
`id` int NOT NULL AUTO_INCREMENT,
`userId` int DEFAULT NULL,
`userRegistrationDate` datetime DEFAULT NULL,
`userFirstName` varchar(25) DEFAULT NULL,
`userSurName` varchar(25) DEFAULT NULL,
`accountBalance` double DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `userUniqueId` (`userId`),
CONSTRAINT `fkUserId` FOREIGN KEY (`userId`) REFERENCES `user_info` (`id`) ON DELETE CASCADE,
CONSTRAINT `chk_accountBalance` CHECK ((`accountBalance` >= 0))
);
所以我有一对一的关系(一个配置文件只与一个用户相关)
这是我的实体:
用户:
@Table("user_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Persistable<Integer> {
@Id
@Column("id")
private Integer id;
@Column("userLogin")
private String userLogin;
@Column("userPassword")
private String userPassword;
@Column("userType")
private String userType;
@Column("userEmail")
private String userEmail;
@Override
public boolean isNew() {
return id==null;
}
}
简介:
@Table("profile_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile implements Persistable<Integer> {
@Id
@Column("id")
private Integer id;
@Column("userRegistrationDate")
private LocalDateTime userRegistrationDate;
@Column("userFirstName")
private String userFirstName;
@Column("userSurName")
private String userSurName;
@Column("accountBalance")
private double accountBalance;
@MappedCollection(idColumn = "id")
private User user;
@Override
public boolean isNew() {
return id==null;
}
}
我使用标准存储库作为 CRUDRepository 用户资料库:
@Repository
public interface UserRepository extends CrudRepository<User,Long> {
}
配置文件存储库:
@Repository
public interface ProfileRepository extends CrudRepository<Profile,Integer> {
}
我有 spring 配置:
@Configuration
@EnableJdbcRepositories("com.example.testrepositories.repository")
public class ApplicationConfig extends AbstractJdbcConfiguration {
@Bean
public DataSource dataSource() {
DriverManagerDataSource managerDataSource = new DriverManagerDataSource();
managerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
managerDataSource.setUrl("jdbc:mysql://localhost:3306/testdatabase");
managerDataSource.setUsername("Bruce");
managerDataSource.setPassword("givanchy");
return managerDataSource;
}
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
我测试存储库的主要方法:
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
ProfileRepository repository = context.getBean("profileRepository",ProfileRepository.class);
User user = new User(null,"TestLogin","testPassword","user","eeed");
Profile profile = new Profile(null, LocalDateTime.now(),"fff","sss",250.0,user);
Profile savedProfile = repository.save(profile);
System.out.println(savedProfile.getId());
System.out.println(savedProfile.getUser().getId());
}
输出为:
在这些操作之后我在数据库中有以下内容:
用户信息已按原样插入
但是在配置文件中没有插入 userId,应该这样吗?
编辑
我将根实体从配置文件更改为用户,效果很好
用户实体:
@Table("user_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Persistable<Integer>{
@Id
@Column("id")
private Integer id;
@Column("userLogin")
private String userLogin;
@Column("userPassword")
private String userPassword;
@Column("userType")
private String userType;
@Column("userEmail")
private String userEmail;
@MappedCollection(keyColumn = "id",idColumn = "userId")
private Profile profile;
@Override
public boolean isNew() {
return id==null;
}
}
个人资料实体:
@Table("profile_info")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Profile implements Persistable<Integer>{
@Id
@Column("id")
private Integer id;
@Column("userRegistrationDate")
private LocalDateTime userRegistrationDate;
@Column("userFirstName")
private String userFirstName;
@Column("userSurName")
private String userSurName;
@Column("accountBalance")
private double accountBalance;
@Override
public boolean isNew() {
return id==null;
}
}
看来一对一关系的使用是错误的。根据您的 ER 图,每个 User
可以有多个 Profile
行。如果是这种情况并且 Profile
是一个聚合(根),那么 user_info
也是一个聚合根。为两个实体都提供一个存储库也是如此。
因此,我们处理聚合之间的引用,这些引用应该仅由 id 表示,而不是对象引用。这意味着您应该制作 Profile.user
和 Integer
或 AggregateReference<Integer>
并在 User
保存后将其设置为 User.id
的值。
一些其他注意事项:
MappedCollection
与简单引用无关。
当 A
引用 B
时,数据库中的外键方向相反。因此,如果 Profile
和 User
确实存在一对一的关系,那么 User
应该是聚合根。
有关所有这些的更多背景信息,请参阅 https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates