在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.userIntegerAggregateReference<Integer> 并在 User 保存后将其设置为 User.id 的值。

一些其他注意事项: MappedCollection 与简单引用无关。 当 A 引用 B 时,数据库中的外键方向相反。因此,如果 ProfileUser 确实存在一对一的关系,那么 User 应该是聚合根。

有关所有这些的更多背景信息,请参阅 https://spring.io/blog/2018/09/24/spring-data-jdbc-references-and-aggregates