Search code examples
javadatabasehibernatejpamany-to-many

Hibernate validator does not see the table


The problem is that with hibernade.ddl-auto: validate enabled, I get an error that the users_roles table does not exist: Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [users_roles] The table was registered in the db migration. Some kind of stupid mistake? I can't find the problem.

Migration code:

create schema if not exists zhem;

create table if not exists zhem.users
(
    user_id    bigserial primary key,
    phone      varchar(11)  not null check ( phone similar to '79[0-9]{9}' ) unique,
    password   varchar(256) not null,
    email      varchar(256) check ( email similar to '([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)' ) unique,
    first_name varchar(32)  not null check ( length(trim(first_name)) >= 2 ),
    last_name  varchar(32) check ( length(trim(last_name)) >= 2 ),
    created_at timestamp default now(),
    updated_at timestamp default now()
);

create table if not exists zhem.roles
(
    role_id serial primary key,
    title   varchar(32) not null check ( length(trim(title)) >= 2 ) unique
);

create table if not exists zhem.users_roles
(
    user_role_id bigserial primary key,
    user_id      bigint not null references zhem.users (user_id),
    role_id      int    not null references zhem.roles (role_id),
    constraint unique_user_id_role_id unique (user_id, role_id)
);

Base entity:

@Data
@MappedSuperclass
public class BaseEntity {

    @CreationTimestamp
    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @UpdateTimestamp
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

}

User:

@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(schema = "zhem", name = "users")
public class User extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long id;

    @CheckPhoneNumber
    @Column(name = "phone", unique = true)
    private String phone;

    @NotBlank
    @Size(max = 256)
    @Column(name = "password")
    private String password;

    @Email
    @Size(max = 256)
    @Column(name = "email", unique = true)
    private String email;

    @NotBlank
    @Size(min = 2, max = 32)
    @Column(name = "first_name")
    private String firstName;

    @Size(min = 2, max = 32)
    @NullOrNotBlank
    @Column(name = "last_name")
    private String lastName;

    @ManyToMany(fetch = FetchType.EAGER)
    private Set<Role> roles;

}

Roles:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(schema = "zhem", name = "roles")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Integer id;

    @NotBlank
    @Size(min = 2, max = 32)
    @Column(name = "title", unique = true)
    private String title;

}

application.yaml:

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/zhem-db
    username: postgres
    password: root
  flyway:
    schemas:
      - public
      - zhem
  jpa:
    hibernate:
      ddl-auto: validate

I tried different ways to link the entity - Unidirectional, Bidirectional, Bidirectional many-to-many with link entity. Nothing changes, the table is still missing.


Solution

  • I think you should specify the @JoinTable parameters to make Hibernate recognize your relation table users_roles.

    public class User extends BaseEntity {
    
    //...
    
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        schema = "zhem",
        name = "users_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles;
    
    //...
    }