是否可以指定使用 Hibernate 将 id 自动增量非空主键设置为 @ManyToMany 关系映射?

Posted

技术标签:

【中文标题】是否可以指定使用 Hibernate 将 id 自动增量非空主键设置为 @ManyToMany 关系映射?【英文标题】:Is it possible specify to set an id auto increment not null primary key into a @ManyToMany relationship mapping using Hibernate? 【发布时间】:2021-12-21 07:11:01 【问题描述】:

我正在开发一个使用 Spring Data JPA 和 Hibernate 来映射预先存在的数据库表的 Spring Boot 应用程序。我发现 @ManyToMany 关系存在一些困难,因为相关关系表具有 bigint 自动增量 NOT NULL PK。

基本上这是我数据库上的关系表:

CREATE TABLE IF NOT EXISTS public.portal_user_user_type
(
    id bigint NOT NULL,
    portal_user_id_fk bigint NOT NULL,
    user_type_id_fk bigint NOT NULL,
    CONSTRAINT portal_user_user_type_pkey PRIMARY KEY (id),
    CONSTRAINT portal_user_user_type_to_portal_user FOREIGN KEY (portal_user_id_fk)
        REFERENCES public.portal_user (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION,
    CONSTRAINT portal_user_user_type_to_user_type FOREIGN KEY (user_type_id_fk)
        REFERENCES public.user_type (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
)

上一张表是我的portal_user表和** user_type**表之间的多对多关联表。这是因为一个用户可以有多个用户类型,并且一个用户类型可以与不同的用户相关。

所以我已将它映射到我的 User 类(映射 portal_user 表),以这种方式:

@SpringBootTest()
@ContextConfiguration(classes = GetUserWsApplication.class)
@TestMethodOrder(OrderAnnotation.class)
public class UserRepositoryTest 
    
    @Autowired
    private UsersRepository userRepository;
    
    
    @Test
    @Order(1)
    public void testInsertUser() 
    
        User user = new User("Mario", null, "Rossi", 'M', new Date(), "XXX", "xxx@gmail.com", "329123456", new Date());
        
        Set<Address> addressesList = new HashSet<>();
        addressesList.add(new Address("Italy", "RM", "00100", "Via XXX 123", "near YYY", user));
        
        user.setAddressesList(addressesList);
        
        Set<UserType> userTypesList = new HashSet<>();
        UserType userType1 = new UserType("ADMIN", "Admin user type !!!");
        UserType userType2 = new UserType("USER", "Just a simple user...");
        
        userTypesList.add(userType1);
        userTypesList.add(userType2);
        
        user.setUserTypes(userTypesList);
        
        userRepository.save(user);
        assertTrue(true);
        
    
    

问题是这个测试方法,当执行 save() 方法时,我得到这个输出,但有以下异常:

Hibernate: 
    insert 
    into
        portal_user
        (birthdate, contact_number, created_at, e_mail, first_name, middle_name, sex, surname, tex_code) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        address
        (country, notes, province, street, fk_user_id, zip_code) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        user_type
        (description, type_name) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        user_type
        (description, type_name) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        portal_user_user_type
        (portal_user_id_fk, user_type_id_fk) 
    values
        (?, ?)
2021-11-08 12:58:50.859  WARN 10724 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 23502
2021-11-08 12:58:50.863 ERROR 10724 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: null value in column "id" of relation "portal_user_user_type" violates not-null constraint
  Detail: Failing row contains (null, 13, 1).
2021-11-08 12:58:50.958  INFO 10724 --- [           main] o.h.e.j.b.internal.AbstractBatchImpl     : HHH000010: On release of batch it still contained JDBC statements

这是因为它似乎无法将记录插入到我的 portal_user_user_type 多对多关系表中,因为该表的 ID 字段不为空。

我知道一个可能的解决方案是删除此 ID 主键字段并创建一个复合 PK(由我的两个字段组成:portal_user_id_fkuser_type_id_fk)。 它可以工作,但我不希望尝试使用这个单独的 id PK 字段。

是否可以指定我的 @ManyToMany 注释以生成自动增量 id 字段?或者有什么可能的解决方案? (我知道我也可以尝试使用两个 @OneToMany 和关联表的另一个实体来实现 Many To Many 关系,但我不希望使用这种方法避免过于复杂)

【问题讨论】:

public.portal_user_user_type 表缺少自增主键。 能否请您发布@Entity 课程UserUserType?这可能会提供一些线索。 【参考方案1】:

您不能直接将自动增量属性添加到 @ManyToMany 注释中,而是应将自动增量 ID 添加到连接的数据库表中,并添加带有 Identity 生成类型的 @GeneratedValue 注释,如下所示:

@Entity
@Table(name = "portal_user_user_type")
public class PortalUserUserType

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

...

【讨论】:

【参考方案2】:

只需让portal_user_user_type 表中的id 自动递增:id bigint NOT NULL GENERATED ALWAYS AS IDENTITY...。然后 Hibernate 将生成一个有效的插入语句而不提及 id。

【讨论】:

以上是关于是否可以指定使用 Hibernate 将 id 自动增量非空主键设置为 @ManyToMany 关系映射?的主要内容,如果未能解决你的问题,请参考以下文章

Org.Hibernate.AnnotationException:没有为实体指定标识符我的表中没有 id

用hibernate保存信息时如何保存自增主键

hibernate 保存的时候ID重复

是否存在使用 Hibernate 指定模式的数据库模式迁移工具?

Hibernate:自定义实体名称

自定义hibernate后端参数验证注解