如何在Kotlin中开始使用Spring Data JPA

在Kotlin中开始使用Spring Data JPA

Spring Data JPA是一套标准,定义了Java对象在数据库中的表现方式。JPA提供了一组注解和接口,使得配置和映射Java对象到关系数据库表成为可能。Java对象之间的关系是通过注释提供的(一对一、一对多、多对一、多对多)。

JPA规范的实现是由 Hibernate 等对象关系映射工具(ORM)提供的。JPA使得在不重构代码的情况下从一个ORM工具切换到另一个ORM工具更加容易,因为它抽象了各种ORM工具所涉及的复杂问题。

JPA位于ORM和应用层之间。在本教程中,我们将使用Spring Data和JPA对一个 Recipe 应用程序进行建模。我们的应用程序的实体关系图如下所示。

在我们开始之前,我们将需要以下条件。

  • 在你的计算机上安装JDK。
  • 最喜欢的IDE。
  • 对[Java]和[Spring Boot]有一定了解。
  • 创建应用程序

    我们将使用[Spring initializr]来创建我们的应用程序。

  • 在浏览器中打开[Spring initializr]。
  • 选择Kotlin语言。
  • 添加 Spring Web , Spring Data JPA , 和 H2 Database 依赖项。
  • 将其他配置保留为默认,然后点击生成项目。
  • 解压下载的项目,在你喜欢的IDE中打开。
  • 将该项目与maven同步,以下载所有的依赖项。
  • 领域包是我们定义模型的地方。

  • 在存在 DemoApplication.kt 文件的根包中,创建一个新包,名称为 domain
  • 在你上面创建的 domain 包中,创建两个Kotlin文件,名称为 Recipe.kt Ingredient.kt
  • JPA映射

    有两种类型的JPA映射。

  • 单向映射 - 这是指JPA映射只在关系的一侧进行。如果实体A与实体B有一对多的关系,那么实体A上只有一对多的关系注解。
  • 双向映射 --这是在相关的两个实体上声明JPA映射的情况。如果实体A与实体B有一对多的关系,那么在实体A上使用一对多的注解,在实体B上使用多对一的注解。这种类型的映射被推荐,因为它使得在两个方向上浏览对象图成为可能。
  • JPA CASCADE类型

    JPA CASCADE类型控制状态变化如何从父对象级联到子对象。

  • PERSIST - 保存操作被级联到相关实体。
  • MERGE - 如果拥有的实体被合并,相关的实体会被合并。
  • REFRESH - 当拥有的实体被刷新时,相关实体被刷新。
  • REMOVE - 当拥有的实体被删除时,删除所有的相关实体。
  • DETACH - 如果发生手动分离,将分离所有相关的实体。
  • ALL - 应用以上所有的级联选项。
  • JPA关系

  • OneToMany关系 在这种类型的JPA关系中,父实体中的一条记录被另一个实体中的许多子记录所引用。从我们上面的实体关系图中,我们可以看到 Recipe 实体与配料实体有一个 OneToMany 的关系,这意味着一份食谱能够有多个配料。
  • 在我们之前创建的 Recipe.kt 文件中,添加下面的代码片段。

        import javax.persistence.*
        @Entity
        data class Recipe(
            @GeneratedValue(strategy = GenerationType.IDENTITY) //Uses underlying persistence framework to generate an Id
            var id: Long?,
            var description: String?,
            var prepTime: String?,
            var cookTime: String?,
            var servings: String?,
            var url: String?,
            var directions: String?,
            @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
            var ingredient: Set<Ingredient>?
    
  • @Entity 注解将 数据类标记为JPA实体,可以持久化到数据库中。Recipe
  • @Id 注释将 字段标记为将从 实体生成的数据库表的主表。id Recipe
  • @GeneratedValue(strategy = GenerationType.IDENTITY) 注释将 字段设置为自动生成,并将 字段标记为唯一。id GenerationType.IDENTITY
  • @OneToMany annotation在 实体和 实体之间创建了一个OneToMany关系。 表明 实体中的 字段是 实体的外键。Recipe Ingredient mappedBy = "recipe" Ingredient recipe Recipe
  • Ingredient.kt 文件中,添加下面的片段。

        @Entity
        data class Ingredient(
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            val id: Long?,
            val description: String?,
            val amount: BigDecimal?,
            @ManyToOne
            val recipe: Recipe
    
  • @ManyToOne 注释创建了一个双向映射,使得在对象图中浏览 和 成为可能。Ingredient Recipe
  • OneToOne关系在这种类型的JPA关系中,一个实体只能属于另一个实体。在我们的Recipe 实体中添加我们将要创建的Note 类型的notes 变量。
  •    @Entity
        data class Recipe(
            @GeneratedValue(strategy = GenerationType.IDENTITY) //Uses underlying   persistence framework to generate an Id
            var id: Long?,
            var description: String?,
            var prepTime: String?,
            var cookTime: String?,
            var servings: String?,
            var url: String?,
            var directions: String?,
            @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
            var ingredient: Set<Ingredient>?,
            @OneToOne(cascade = [CascadeType.ALL])
            var notes: Notes?,//Foreign Key
    
  • @OneToOne 注解表示 实体将与 实体有一对一的关系。Notes Recipe
  • domain 包中,创建一个Kotlin文件,名称为Notes.kt 。在创建的Notes.kt 文件中,添加下面的代码片断。

        @Entity
        data class Notes(
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            var id: Long?,
            @OneToOne
            var recipe: Recipe?,
            @Lob //Allows for more than 256 characters in the notes field as hibernate always limits the String field to 256 characters.
            var notes: String?
    
  • @OneToOne 注解与 实体创建一个双向的映射关系。Recipe
  • ManyToMany关系在这种类型的JPA关系中,一个实体的一条或多条记录与另一个实体的一条或多条记录相关联。
  • 从我们的实体关系图中,我们看到Recipe 实体与Category 实体有一个ManyToMany的关系,这意味着一个菜谱可以属于许多类别,反之亦然。

    domain 包中创建一个Kotlin文件,名称为Category.kt 。在Category.kt 文件中添加下面的代码片段。

        @Entity
        data class Category(
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            val id: Long,
            val name: String,
            @ManyToMany(mappedBy = "category")
            val recipe: Set<Recipe>
    

    Recipe 实体中,添加category 字段,并使用@ManyToMany 注解对其进行注释。

        @Entity
        data class Recipe(
            @GeneratedValue(strategy = GenerationType.IDENTITY) //Uses underlying   persistence framework to generate an Id
            var id: Long?,
            var description: String?,
            var prepTime: String?,
            var cookTime: String?,
            var servings: String?,
            var url: String?,
            var directions: String?,
            @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
            var ingredient: Set<Ingredient>?,
            @OneToOne(cascade = [CascadeType.ALL])
            var notes: Notes?,//Foreign Key
            @ManyToMany
            @JoinTable(
            name = "recipe_category",
            joinColumns = [JoinColumn(name = "recipe_id")],
            inverseJoinColumns = [JoinColumn(name = "category_id")]
            val category: Set<Category>?
    
  • @JoinTable 注解生成了一个名为recipe_category 的表,该表将存储RecipeCategory 的主键。生成的表有两列;recipe_id ,引用Recipe 表中的id;category_id ,引用Category 表中的id列。
  • Enumerated用于在JPA中存储映射枚举值到数据库的表示。
  • domain 包中创建一个Kotlin枚举类,名称为Difficulty 。将下面的代码片段添加到上面创建的枚举类中。

        enum class Difficulty {
            EASY, MODERATE, HARD
    

    Recipe 实体中添加难度类型的difficulty 字段,如下所示。

        @Entity
        data class Recipe(
            @GeneratedValue(strategy = GenerationType.IDENTITY) //Uses underlying   persistence framework to generate an Id
            var id: Long?,
            var description: String?,
            var prepTime: String?,
            var cookTime: String?,
            var servings: String?,
            var url: String?,
            var directions: String?,
            @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
            var ingredient: Set<Ingredient>?,
            @OneToOne(cascade = [CascadeType.ALL])
            var notes: Notes?,//Foreign Key
            @ManyToMany
            @JoinTable(
            name = "recipe_category",
            joinColumns = [JoinColumn(name = "recipe_id")],
            inverseJoinColumns = [JoinColumn(name = "category_id")]
            val category: Set<Category>?,
            @Enumerated(value = EnumType.STRING)
            val difficulty: Difficulty,
    
  • @Enumerated(value = EnumType.STRING) 将困难字段设置为枚举。有两种枚举类型;EnumType.STRINGEnumType.ORDINAL
  • EnumType.ORDINAL 枚举值以整数形式存储,即: 为1, 为3,而 以字符串形式存储,即: 为EASY。EASY HARD EnumType.STRING EASY
  • 现在你已经学会了如何使用Spring Data JPA对数据库进行建模,实现JPA存储库,然后为我们的食谱应用程序创建一个REST控制器。

    分类:
    后端
  •