JPA重整ORM山河
【IT168分析评论】
3.使用注解元数据
基本注解
首先,我们对Topic领域对象进行注解,使其成为一个合格的实体类:
代码清单 1 Topic实体类的注解
@Entity:将领域对象标注为一个实体,表示需要保存到数据库中,默认情况下类名即为表名,通过name属性显式指定表名,如①处的name = "T_TOPIC",表示Topic保存到T_TOPIC表中;package com.baobaotao.domain;
…
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
![]()
@Entity(name = "T_TOPIC") ①
public class Topic implements Serializable ...{
@Id ②-1
@GeneratedValue(strategy = GenerationType.TABLE) ②-2
@Column(name = "TOPIC_ID") ②-3
private int topicId;
![]()
@Column(name = "TOPIC_TITLE", length = 100) ③
private String topicTitle;
![]()
@Column(name = "TOPIC_TIME")
@Temporal(TemporalType.DATE) ④
private Date topicTime;
![]()
@Column(name = "TOPIC_VIEWS")
private int topicViews;
![]()
//省略get/setter方法
}
@Id :对应的属性是表的主键,如②-1所示;
@GeneratedValue:主键的产生策略,通过strategy属性指定。默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略,如SqlServer对应identity,MySql对应auto increment。在javax.persistence.GenerationType中定义了以下几种可供选择的策略:
1) IDENTITY:表自增键字段,Oracle不支持这种方式;
2) AUTO: JPA自动选择合适的策略,是默认选项;
3) SEQUENCE:通过序列产生主键,通过@SequenceGenerator注解指定序列名,MySql不支持这种方式;
4) TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。不同的JPA实现商生成的表名是不同的,如OpenJPA生成openjpa_sequence_table表Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。
@Column(name = "TOPIC_ID"):属性对应的表字段。我们并不需要指定表字段的类型,因为JPA会根据反射从实体属性中获取类型;如果是字符串类型,我们可以指定字段长度,以便可以自动生成DDL语句,如③处所示;
@Temporal(TemporalType.DATE):如果属性是时间类型,因为数据表对时间类型有更严格的划分,所以必须指定具体时间类型,如④所示。在javax.persistence.TemporalType枚举中定义了3种时间类型:
1) DATE :等于java.sql.Date
2) TIME :等于java.sql.Time
3) TIMESTAMP :等于java.sql.Timestamp
继承关系
Topic和PollTopic是父子类,JPA 采用多种方法来支持实体继承。在父类中必须声明继承实体的映射策略,如代码清单 2所示:
代码清单 2:继承实体的映射策略
对于继承的实体,在javax.persistence.InheritanceType定义了3种映射策略,:…
@Entity(name = "T_TOPIC")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) ①
@DiscriminatorColumn(name = "TOPIC_TYPE", discriminatorType =
DiscriminatorType.INTEGER, length = 1) ②@DiscriminatorValue(value="1")③
public class Topic implements Serializable ...{
…
}
SINGLE_TABLE:父子类都保存到同一个表中,通过字段值进行区分。这是我们Topic实体所采用的策略,Topic和PollTopic都保存到同一张表中,通过TOPIC_TYPE字段进行区分,Topic在T_TOPIC表中对应TOPIC_TYPE=1的记录,而PollTopic对应TOPIC_TYPE=2的记录(稍后在PollTopic实体中指定);区别的字段通过@DiscriminatorColumn说明,如②所示,区分字段对应该实体的值通过@DiscriminatorValue指定,如③所示;
JOINED:父子类相同的部分保存在同一个表中,不同的部分分开存放,通过表连接获取完整数据;
TABLE_PER_CLASS:每一个类对应自己的表,一般不推荐采用这种方式。
关联关系
我们再继续对PollTopic进行注解,进一步了解实体继承的JPA映射定义:
代码清单 3 PollTopic映射描述
在①处,通过@DiscriminatorValue将区分字段TOPIC_TYPE的值为2。由于PollTopic实体继承于Topic实体,其它的元数据信息直接从Topic获得。package com.baobaotao.domain;
…
@Entity
@DiscriminatorValue(value="2") ①
public class PollTopic extends Topic ...{②继承于Topic实体
private boolean multiple; ③
@Column(name = "MAX_CHOICES")
private int maxChoices;
@OneToMany(mappedBy="pollTopic",cascade=CascadeType.ALL) ④
private Set<PollOption> options = new HashSet<PollOption>();
//省略get/setter方法
}
JPA规范规定任何属性都默认映射到表中,所以虽然我们没有给③处的multiple属性提供注解信息,但JPA将按照默认的规则对该字段进行映射:字段名和属性名相同,类型相同。如果我们不希望将某个属性持久化到数据表中,则可以通过@Transient注解显式指定:
@Transient
private boolean tempProp1;
在④处,我们通过@OneToMany指定了一个一对多的关联关系,一个PollTopic包括多个PollOption对象(我们将在稍后的PollOption中通过ManyToOne描述PollOption和PollTopic的关系,以建立PollTopic和PollOption的双向关联关系)。
@OneToMany中通过mappedBy属性指定“Many”方类引用“One”方类的属性名,这里mappedBy="pollTopic"表示PollOption实体拥有一个指定PollTopic的pollTopic属性。
下面,我们来看一下Many方PollOption实体类的映射描述:
代码清单 4 PollOption映射描述
在①处通过@ManyToOne描述了PollOption和PollTopic的多对一关联关系,并通过@JoinColumn指定关联PollTopic实体所对应表的“外键”,如②所示。package com.baobaotao.domain;
…
@Entity(name="T_POLL_OPTION")
public class PollOption implements Serializable ...{
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "OPTION_ID")
private int optionId;
![]()
@Column(name = "OPTION_ITEM")
private String optionItem;
![]()
@ManyToOne ①
@JoinColumn(name="TOPIC_ID", nullable=false) ②
private PollTopic pollTopic;
}
当然也可以通过@OneToOne和@ManyToMany指定一对一和多以多的关系,方法差不多,不再赘述。
0
相关文章
