3.2.2 注解域作为实体
很快就会看到,在创建存储库方面,Spring Data 做了一些惊人的事情。但不幸的是,在使用 JPA 映射注解注解域对象时,它并没有太大的帮助。需要打开 Ingredient、Taco 和 Order 类,并添加一些注解。首先是 Ingredient 类。
程序清单 3.16 为 JPA 持久化注解 Ingredient
1
package tacos;
2
3
import javax.persistence.Entity;
4
import javax.persistence.Id;
5
import lombok.AccessLevel;
6
import lombok.Data;
7
import lombok.NoArgsConstructor;
8
import lombok.RequiredArgsConstructor;
9
10
@Data
11
@RequiredArgsConstructor
12
@NoArgsConstructor(access=AccessLevel.PRIVATE, force=true)
13
@Entity
14
public class Ingredient {
15
@Id
16
private final String id;
17
private final String name;
18
private final Type type;
19
20
public static enum Type {
21
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
22
}
23
}
Copied!
为了将其声明为 JPA 实体,必须使用 @Entity 注解。它的 id 属性必须使用 @Id 进行注解,以便将其指定为惟一标识数据库中实体的属性。
除了特定于 JPA 的注解之外,还在类级别上添加了 @NoArgsConstructor 注解。JPA 要求实体有一个无参构造函数,所以 Lombok 的 @NoArgsConstructor 实现了这一点。但是要是不希望使用它,可以通过将 access 属性设置为 AccessLevel.PRIVATE 来将其设置为私有。因为必须设置 final 属性,所以还要将 force 属性设置为 true,这将导致 Lombok 生成的构造函数将它们设置为 null。
还添加了一个 @RequiredArgsConstructor。@Data 隐式地添加了一个必需的有参构造函数,但是当使用 @NoArgsConstructor 时,该构造函数将被删除。显式的 @RequiredArgsConstructor 确保除了私有无参数构造函数外,仍然有一个必需有参构造函数。
现在让我们转到 Taco 类,看看如何将其注解为 JPA 实体。
程序清单 3.17 把 Taco 注解为实体
1
package tacos;
2
3
import java.util.Date;
4
import java.util.List;
5
import javax.persistence.Entity;
6
import javax.persistence.GeneratedValue;
7
import javax.persistence.GenerationType;
8
import javax.persistence.Id;
9
import javax.persistence.ManyToMany;
10
import javax.persistence.OneToMany;
11
import javax.persistence.PrePersist;
12
import javax.validation.constraints.NotNull;
13
import javax.validation.constraints.Size;
14
import lombok.Data;
15
16
@Data
17
@Entity
18
public class Taco {
19
20
@Id
21
@GeneratedValue(strategy=GenerationType.AUTO)
22
private Long id;
23
24
@NotNull
25
@Size(min=5, message="Name must be at least 5 characters long")
26
private String name;
27
28
private Date createdAt;
29
30
@ManyToMany(targetEntity=Ingredient.class)
31
@Size(min=1, message="You must choose at least 1 ingredient")
32
private List<Ingredient> ingredients;
33
34
@PrePersist
35
void createdAt() {
36
this.createdAt = new Date();
37
}
38
}
Copied!
与 Ingredient 一样,Taco 类现在使用 @Entity 注解,其 id 属性使用 @Id 注解。因为依赖于数据库自动生成 id 值,所以还使用 @GeneratedValue 注解 id 属性,指定自动策略。
要声明 Taco 及其相关 Ingredient 列表之间的关系,可以使用 @ManyToMany 注解 ingredient 属性。一个 Taco 可以有很多 Ingredient,一个 Ingredient 可以是很多 Taco 的一部分。
还有一个新方法 createdAt(),它用 @PrePersist 注解。将使用它将 createdAt 属性设置为保存 Taco 之前的当前日期和时间。最后,让我们将 Order 对象注解为一个实体。下一个程序清单展示了新的 Order 类。
程序清单 3.18 把 Order 注解为 JPA 实体
1
package tacos;
2
3
import java.io.Serializable;
4
import java.util.ArrayList;
5
import java.util.Date;
6
import java.util.List;
7
import javax.persistence.Entity;
8
import javax.persistence.GeneratedValue;
9
import javax.persistence.GenerationType;
10
import javax.persistence.Id;
11
import javax.persistence.ManyToMany;
12
import javax.persistence.OneToMany;
13
import javax.persistence.PrePersist;
14
import javax.persistence.Table;
15
import javax.validation.constraints.Digits;
16
import javax.validation.constraints.Pattern;
17
import org.hibernate.validator.constraints.CreditCardNumber;
18
import org.hibernate.validator.constraints.NotBlank;
19
import lombok.Data;
20
21
@Data
22
@Entity
23
@Table(name="Taco_Order")
24
public class Order implements Serializable {
25
private static final long serialVersionUID = 1L;
26
27
@Id
28
@GeneratedValue(strategy=GenerationType.AUTO)
29
private Long id;
30
31
private Date placedAt;
32
33
...
34
35
@ManyToMany(targetEntity=Taco.class)
36
private List<Taco> tacos = new ArrayList<>();
37
38
public void addDesign(Taco design) {
39
this.tacos.add(design);
40
}
41
42
@PrePersist
43
void placedAt() {
44
this.placedAt = new Date();
45
}
46
}
Copied!
对 Order 的更改与对 Taco 的更改非常相似。但是在类级别有一个新的注解:@Table。这指定订单实体应该持久化到数据库中名为 Taco_Order 的表中。
尽管可以在任何实体上使用这个注解,但它对于 Order 是必需的。没有它,JPA 将默认将实体持久化到一个名为 Order 的表中,但是 Order 在 SQL 中是一个保留字,会导致问题。现在实体已经得到了正确的注解,该编写 repository 了。
复制链接