在Kotlin中开始使用Spring Data JPA
Spring Data JPA是一套标准,定义了Java对象在数据库中的表现方式。JPA提供了一组注解和接口,使得配置和映射Java对象到关系数据库表成为可能。Java对象之间的关系是通过注释提供的(一对一、一对多、多对一、多对多)。
JPA规范的实现是由 Hibernate 等对象关系映射工具(ORM)提供的。JPA使得在不重构代码的情况下从一个ORM工具切换到另一个ORM工具更加容易,因为它抽象了各种ORM工具所涉及的复杂问题。
JPA位于ORM和应用层之间。在本教程中,我们将使用Spring Data和JPA对一个
Recipe
应用程序进行建模。我们的应用程序的实体关系图如下所示。
在我们开始之前,我们将需要以下条件。
创建应用程序
我们将使用[Spring initializr]来创建我们的应用程序。
Spring Web
,
Spring Data JPA
, 和
H2 Database
依赖项。
领域包是我们定义模型的地方。
DemoApplication.kt
文件的根包中,创建一个新包,名称为
domain
。
domain
包中,创建两个Kotlin文件,名称为
Recipe.kt
和
Ingredient.kt
。
JPA映射
有两种类型的JPA映射。
JPA CASCADE类型
JPA CASCADE类型控制状态变化如何从父对象级联到子对象。
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
的表,该表将存储Recipe
和Category
的主键。生成的表有两列;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.STRING
和EnumType.ORDINAL
。
EnumType.ORDINAL
枚举值以整数形式存储,即: 为1, 为3,而 以字符串形式存储,即: 为EASY。EASY
HARD
EnumType.STRING
EASY
现在你已经学会了如何使用Spring Data JPA对数据库进行建模,实现JPA存储库,然后为我们的食谱应用程序创建一个REST控制器。