jakarta.persistence.Check constraint not working

huangapple go评论82阅读模式
英文:

jakarta.persistence.Check constraint not working

问题

I have the following Movie class in a Spring Boot project that holds a list of actors. I wanted to make sure an actor won't be deleted if it's part of a movie, and I want to enforce this constraint on a database level using JPA/Hibernate. However, when I import jakarta.persistence.Check, the compiler is not recognizing it even though I have the right dependency in Gradle. I assume this is a versioning issue, but I couldn't resolve it.

import jakarta.persistence.*;
import jakarta.persistence.Check;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "movies",
        uniqueConstraints = @UniqueConstraint(columnNames = {"title", "releaseDate"}))
public class Movie extends Media {

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private LocalDate releaseDate;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "movie_actor",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name = "actor_id"),
            uniqueConstraints = {@UniqueConstraint(columnNames = {"movie_id", "actor_id"})},
            foreignKey = @ForeignKey(name = "fk_movie"),
            inverseForeignKey = @ForeignKey(name = "fk_actor"),
            // add check constraint to ensure actor is not deleted if part of any movie
            constraints = @Check(constraints = "NOT EXISTS(SELECT * FROM movie_actor ma WHERE ma.actor_id = id)")
    )
    private Set<Actor> actors = new HashSet<>();
}

Here is my build.gradle file:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.5'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'io.freefair.lombok' version '8.0.1'
}

group = 'com.bill'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
    //jcenter()
}

dependencies {
    implementation 'org.springframework.data:spring-data-jpa:3.0.4'
    implementation 'javax.persistence:javax.persistence-api:2.2'
    implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
    implementation 'jakarta.validation:jakarta.validation-api:3.0.2'
    implementation 'org.springframework.boot:spring-boot-starter-validation:2.6.3'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'mysql:mysql-connector-java:8.0.32'
    implementation 'org.hibernate:hibernate-core:5.5.7.Final'
    implementation 'org.hibernate:hibernate-entitymanager:5.5.7.Final'

    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

tasks.withType(JavaCompile) {
    options.annotationProcessorPath = configurations.compileClasspath
}
英文:

I have the following Movie class in a Spring Boot project that holds list of actors. I wanted to make sure an actor wont be deleted if its part of a movie and I want to enforce this constraint on a database level by JPA/Hibernate. However when I import jakarta.persistence.Check the complier is not recognizing it even if I had the right dependency in gradle. I assume this is versioning issue but I couldn't get it resolved.

    import jakarta.persistence.*;
    import jakarta.persistence.Check;
    
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    import java.time.LocalDate;
    import java.util.HashSet;
    import java.util.Set;
    
    @Entity
    @Table(name = &quot;movies&quot;,
            uniqueConstraints = @UniqueConstraint(columnNames = {&quot;title&quot;, &quot;releaseDate&quot;}))
public class Movie extends Media {

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private LocalDate releaseDate;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = &quot;movie_actor&quot;,
            joinColumns = @JoinColumn(name = &quot;movie_id&quot;),
            inverseJoinColumns = @JoinColumn(name = &quot;actor_id&quot;),
            uniqueConstraints = {@UniqueConstraint(columnNames = {&quot;movie_id&quot;, &quot;actor_id&quot;})},
            foreignKey = @ForeignKey(name = &quot;fk_movie&quot;),
            inverseForeignKey = @ForeignKey(name = &quot;fk_actor&quot;),
            // add check constraint to ensure actor is not deleted if part of any movie
            constraints = @Check(constraints = &quot;NOT EXISTS(SELECT * FROM movie_actor ma WHERE ma.actor_id = id)&quot;)
    )
    private Set&lt;Actor&gt; actors = new HashSet&lt;&gt;();
}

Here is my gradle.build file:

plugins {
    id &#39;java&#39;
    id &#39;org.springframework.boot&#39; version &#39;3.0.5&#39;
    id &#39;io.spring.dependency-management&#39; version &#39;1.1.0&#39;
    id &#39;io.freefair.lombok&#39; version &#39;8.0.1&#39;
}

group = &#39;com.bill&#39;
version = &#39;0.0.1-SNAPSHOT&#39;
sourceCompatibility = &#39;17&#39;

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
    //jcenter()
}

dependencies {
    implementation &#39;org.springframework.data:spring-data-jpa:3.0.4&#39;
    implementation &#39;javax.persistence:javax.persistence-api:2.2&#39;
    implementation &#39;jakarta.persistence:jakarta.persistence-api:3.1.0&#39;
    implementation &#39;jakarta.validation:jakarta.validation-api:3.0.2&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-validation:2.6.3&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    implementation &#39;org.springframework.boot:spring-boot-starter-data-jpa&#39;
    implementation &#39;mysql:mysql-connector-java:8.0.32&#39;
    implementation &#39;org.hibernate:hibernate-core:5.5.7.Final&#39;
    implementation &#39;org.hibernate:hibernate-entitymanager:5.5.7.Final&#39;

/*

 */

    compileOnly &#39;org.projectlombok:lombok&#39;
    developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;
    annotationProcessor &#39;org.springframework.boot:spring-boot-configuration-processor&#39;
    annotationProcessor &#39;org.projectlombok:lombok&#39;
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
}

tasks.named(&#39;test&#39;) {
    useJUnitPlatform()
}

tasks.withType(JavaCompile) {
    options.annotationProcessorPath = configurations.compileClasspath
}

答案1

得分: 3

Jakarta Persistence API从未定义@Check注解。因此,jakarta.persistence.Check既在2.3规范中也不在3.x规范中存在。最新规范可在此处找到,源代码在这里

我假设您想要使用org.hibernate.annotations.Check
有关更多信息,请查看此链接:https://docs.jboss.org/hibernate/orm/5.5/userguide/html_single/Hibernate_User_Guide.html#schema-generation-database-checks。

最后,我想指出代码的一些重要部分。

  1. Hibernate Entitymanager 5.5.7已经进入了生命周期的终点。这个版本不再受支持。我强烈建议升级此依赖项。
  2. spring-data-jpa:3.0.4具有一个可选依赖项hibernate-core:6.1.4.Final。这是因为我建议使用Hibernate 6.x。
  3. 您在依赖项中定义了两个不兼容的JPA API:javax.persistence:javax.persistence-api:2.2jakarta.persistence:jakarta.persistence-api:3.1.0。Spring Framework 6和Spring Boot 3都完全兼容Jakarta EE 9。在Jakarta堆栈上使用任何javax.*依赖项可能会引发问题。
英文:

Jakarta Persistence API have never defined @Check annotation. So, jakarta.persistence.Check doesn't exsist neither in 2.3 nor 3.x specification. The latest specification is available here and the source code is here.

I assume you would like to use org.hibernate.annotations.Check
For further information, follow this link: https://docs.jboss.org/hibernate/orm/5.5/userguide/html_single/Hibernate_User_Guide.html#schema-generation-database-checks.

Finally, I'd like to point out some important parts of this code.

  1. Hibernate Entitymanager 5.5.7 reached the End Of Life phase. This version is no longer supported. I strongly recommend to upgrade this dependency.
  2. spring-data-jpa:3.0.4 has an optional dependency hibernate-core:6.1.4.Final. That's because I recommend use Hibernate 6.x.
  3. You've defined two incompatible JPA API in the dependencies: javax.persistence:javax.persistence-api:2.2 and jakarta.persistence:jakarta.persistence-api:3.1.0 Both Spring Framework 6 and Spring Boot 3 are fully Jakarta EE 9 compatible. On Jakarta stack using any javax.* dependency may cause problems.

huangapple
  • 本文由 发表于 2023年4月17日 00:22:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76028971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定