为什么我在尝试实现 Hibernate 多对多映射时遇到此错误?

Why I am obtaining this error trying to implement an Hibernate Many To Many mapping?

我正在使用 Spring Data Jpa 开发一个 Spring 引导项目,以便在我的 PostgreSQL 数据库中持久保存数据。 我发现 Hibernate Many To Many 映射有些困难。以下是我的问题的详细信息。在我的项目中,tables 不是由 Hibernate 创建的,但我正在使用 Hibernate 定义实体 classes 映射我的 tables.

我有这 3 个数据库 tables:

好的,那么我已经将前面的 3 个 classes 映射到以下实体 classes:

用户class映射portal_usertable:

@Entity
@Table(name = "portal_user")
@Data
public class User implements Serializable {
     
    private static final long serialVersionUID = 5062673109048808267L;
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "middle_name")
    private String middleName;
    
    @Column(name = "surname")
    private String surname;
    
    @Column(name = "sex")
    private char sex;
    
    @Column(name = "birthdate")
    private Date birthdate;
    
    @Column(name = "tex_code")
    private String taxCode;
    
    @Column(name = "e_mail")
    private String eMail;
    
    @Column(name = "contact_number")
    private String contactNumber;
    
    @Temporal(TemporalType.DATE)
    @Column(name = "created_at")
    private Date createdAt;
    
    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
    @JsonManagedReference
    private Set<Address> addressesList = new HashSet<>();
    
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    @JsonManagedReference
    private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();

    public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
            String eMail, String contactNumber, Date createdAt) {
        super();
        this.firstName = firstName;
        this.middleName = middleName;
        this.surname = surname;
        this.sex = sex;
        this.birthdate = birthdate;
        this.taxCode = taxCode;
        this.eMail = eMail;
        this.contactNumber = contactNumber;
        this.createdAt = createdAt;
    }
        
}

NOTE-1:这个 @OneToMany 关系与另一个用例相关并且工作正常(所以它不是这个的一部分问题):

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();

NOTE-2User class 包含此 @OneToMany实现我的 多对多 关系一侧的关系导致问题:

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
@JsonManagedReference
private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();

User_UserType class 是实体 class 映射我的多对多关系。

然后我有 UserType 实体 classes 映射之前的 user_type DB table:

@Entity
@Table(name = "user_type")
@Data
public class UserType implements Serializable {
    
    private static final long serialVersionUID = 6904959949570501298L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "name")
    private String name;
    
    @Column(name = "description")
    private String description;
    
    @OneToMany(mappedBy = "userType")
    @JsonManagedReference
    private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();
    

    public UserType() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public UserType(String name, String description) {
        super();
        this.name = name;
        this.description = description;
    }


}

注意:这个class包含这个@OneToMany关系代表Many的另一边对我要实现的许多 关系。

@OneToMany(mappedBy = "userType")
@JsonManagedReference
private Set<User_UserType> userToUserTypeAssociation = new HashSet<>();

然后我实现了 User_UserType 实体 class 映射 portal_user_user_type(我的多对多关联 table):

@Entity
@Table(name = "portal_user_user_type")
@Data
public class User_UserType implements Serializable {

    private static final long serialVersionUID = -1334879762781878984L;
    
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @ManyToOne()
    @JoinColumn(name = "portal_user_id_fk")
    @JsonBackReference
    private User user;
    
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "user_type_id_fk")
    @JsonBackReference
    private UserType userType;

    public User_UserType() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public User_UserType(User user, UserType userType) {
        super();
        this.user = user;
        this.userType = userType;
    }

}

注意:这个class包含两个指向相关@ManyToOne()关系UserUserType 实例。

最后我尝试通过 JUnit 测试方法对其进行测试,这个:

@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_UserType user_UserType1 = new User_UserType(user, userType1);
        User_UserType user_UserType2 = new User_UserType(user, userType2);
        
        Set<User_UserType> user_UserType_List = new HashSet<>();
        user_UserType_List.add(user_UserType1);
        user_UserType_List.add(user_UserType2);
        
        user.setUserToUserTypeAssociation(user_UserType_List);
        
        userRepository.save(user);
        assertTrue(true);
        
    }
    
}

运行此方法Spring开机启动无错误信息。 运行 它在调试模式下到达 save() 方法执行,我试图在其中保存我的 User 实例(期望定义的关系也被保存:所以两个创建的用户类型和关系进入我的关联 table).

这里发生了一些奇怪的事情。 save 方法似乎给了我一个异常(我可以在调试模式下看到它)但我在堆栈跟踪中没有收到任何错误消息。按照我得到的打印屏幕:

如您所见,它进入了荧光笔异常,但是 运行 应用程序在堆栈跟踪中结束,没有与此异常相关的错误行。这是我从 Spring 引导启动到结束的整个堆栈跟踪:

 /\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.6)

2021-11-06 19:09:01.145  INFO 22688 --- [           main] c.e.u.t.R.UserRepositoryTest             : Starting UserRepositoryTest using Java 16.0.1 on ubuntu with PID 22688 (started by andrea in /home/andrea/git/get-user-ws)
2021-11-06 19:09:01.148  INFO 22688 --- [           main] c.e.u.t.R.UserRepositoryTest             : No active profile set, falling back to default profiles: default
2021-11-06 19:09:01.896  INFO 22688 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2021-11-06 19:09:01.957  INFO 22688 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 53 ms. Found 2 JPA repository interfaces.
2021-11-06 19:09:02.805  INFO 22688 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2021-11-06 19:09:02.871  INFO 22688 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.32.Final
2021-11-06 19:09:03.071  INFO 22688 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-11-06 19:09:03.211  INFO 22688 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-11-06 19:09:03.456  INFO 22688 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2021-11-06 19:09:03.487  INFO 22688 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
2021-11-06 19:09:04.193  INFO 22688 --- [           main] org.hibernate.tuple.PojoInstantiator     : HHH000182: No default (no-argument) constructor for class: com.easydefi.users.entity.User (class must be instantiated by Interceptor)
2021-11-06 19:09:04.323  INFO 22688 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-11-06 19:09:04.330  INFO 22688 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-11-06 19:09:04.553  WARN 22688 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2021-11-06 19:09:05.626  INFO 22688 --- [           main] c.e.u.t.R.UserRepositoryTest             : Started UserRepositoryTest in 4.96 seconds (JVM running for 6.304)
2021-11-06 19:11:09.255  INFO 22688 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2021-11-06 19:11:09.257  INFO 22688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2021-11-06 19:11:09.264  INFO 22688 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

那么我的代码有什么问题?我错过了什么?我该如何修复它?如果抛出此异常,为什么我没有在堆栈跟踪中获取错误行?

portal_user_user_type 中的 ID 应该是自动生成的,但 id bigint NOT NULL?

但是 portal_user_user_type 只包含对 UserUserType 的引用。这样您就可以轻松地简化您的模型。

类似于:

class User {
    
    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(
        name = "portal_user_user_type", 
        joinColumns = { @JoinColumn(name = "portal_user_id_fk") }, 
        inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
    )
    Set<UserType> userTypes;