`
forge
  • 浏览: 23119 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

三.对象关系映射-part2

    博客分类:
  • JPA
阅读更多

基本映射

 

一、 @Table

 

@javax.persistence.Table 注解可以改变实体类默认映射的表名

book 实体映射给 T_BOOK

 

@Entity
@Table(name = "t_book")
public class Book {
	@Id
	private Long id;
	private String title;
	private Float price;
	private String description;
	private String isbn;
	private Integer nbOfPage;
	private Boolean illustrations;

	public Book() {
	}
	// Getters, setters
}
 

 

注意,根据数据库的不同,实体类默认映射到数据库的表名,有可能全大写,有可能全小写。


 

二、 @SecondaryTable


我们可以用该注解定义实体关联的一个或多个次表,用 @Column(table = "XXX") 指定属性指向的次表,看下面的例子:

 

@Entity
@SecondaryTables({ @SecondaryTable(name = "city"),
		@SecondaryTable(name = "country") })
public class Address {
	@Id
	private Long id;
	private String street1;
	private String street2;
	@Column(table = "city")
	private String city;
	@Column(table = "city")
	private String state;
	@Column(table = "city")
	private String zipcode;
	@Column(table = "country")
	private String country;
	// Constructors, getters, setters
}

 

 

该实体映射图:

 

 

 

每个表都有相同的主键。

注意:当使用次表时,你应该考虑性能问题。每次你访问这样的一个实体,持久化实现类访问多个表,用 join 的方式将他们关联。当你有大数据对象 (BLOBs), 用次表将大数据对象隔离是很好的。


三、主键


@javax.persistence.Id 注释属性可以是以下类型:


1. 基本 Java 类型: byte,int,short,long,char

2. 包装的基本 Java 类型: Byte,Integer,Short,Long,Character

3. 基本 Java 类型或包装的基本 Java 类型数组 :int[],Integer[] 等等。

4. 字符串,数字类型和日期 :java.lang.String,java.math.BigInteger,java.util.Date,java.sql.Date


主键值可以手动赋值,也可以通过 @GeneratedValue 注解自动赋值。该注解有 4 个值:


  1. SEQUENCE IDENTITY 是根据数据库的 sequence identity 自增主键值

  2. TABLE 是用数据库表来储存主键 ( 主键名和主键值 )

  3. AUTO 是默认值,根据特定数据库选择相应的主键生成策略


四、复合主键


JPA 里我们有 2 种方式定义主键: @EmbeddedId @IdClass

通常将复合主键相关属性,单独抽取出来,建立一个独立的类,这个类就是主键类,要求:

1. 复合主键必须重写 equals hashcode 方法 (JPA 查找缓存的持久化对象 )

2. 必须实现 Serializable 接口


@EmbeddedId

查看下例:

 

@Embeddable
public class NewsId implements Serializable{
	private String title;
	private String language;
	// Constructors, getters, setters, equals, and hashcode
}

 

@Entity
public class News {
	@EmbeddedId
	private NewsId id;
	private String content;
	// Constructors, getters, setters
}

 

 

 

看看我们怎么用复合主键查询:


NewsId pk = new NewsId("Richard Wright has died", "EN")

News news = em.find(News.class, pk);


@IdClass


以这种方式的复合主键类不需要任何注解:

 

public class NewsId implements Serializable{
	private String title;
	private String language;
	// Constructors, getters, setters, equals, and hashcode
}
 
@Entity
@IdClass(NewsId.class)
public class News {
	@Id
	private String title;
	@Id
	private String language;
	private String content;
	// Constructors, getters, setters, equals, and hashcode
}

 

 

@EmbeddedId @IdClass 这两种方式都被映射为同一个表结构

 

CREATE TABLE `news` (
  `language` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  `content` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`language`,`title`)
) 

 

 

明显的不同是 JPQL 查询:


@IDClass 时:

select n.title from News n


@EmbeddedID 时:

select n.newsId.title from News n



五、属性


实体属性可以是以下类型:

  1. Java 基本数据类型 (int,double,float ) 及其包装类 (Integer,Double,Float )

  2. 字节和字符数组 (byte[],Byte[],char[],Character[])

  3. 字符串,大数据类型,时间类型 (java.lang.String,java.math.BigInteger,java.math.BigDecimal,java.util.Date,java.util.Calendar,java.sql.Date,java.sql.Time,java.sql.Timestamp)

  4. 枚举类和用户自定义实现 Serialiable 接口类型

  5. 基础集合类和嵌入类型


六、 @Basic


可选注解 @javax.persistence.Basic 是映射数据库列的最基本类型。

 

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Basic {

    FetchType fetch() default EAGER;

    boolean optional() default true;
}

 

 

这个注解有 2 个参数: optional fetch.


optional 元素指定属性的值是否为空 ( 忽略基本类型,因为基本类型是非空类型 )

fetch 元素有 2 个值: LAZY EAGER 。指定属性数据是否是懒加载或立即加载。


比如我们有一个 Track( 音轨 ) 实体,有一个 WAV 属性 (WAV 文件是一个 BLOB ,可能有几兆 ) ,当我们访问 Track 实体时,我们不想立即加载 WAV 文件。

 

@Entity
public class Track {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	
	private String title;
	private float duration;
	@Basic(fetch = FetchType.LAZY)
	@Lob
	private byte[] wav;
	private String description;
	
	// Constructors, getters, setters
	
}

 

 

七、 @Column


@Column 注解元素

 

 

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Column {

    String name() default "";

    /**
     * (Optional) Whether the column is a unique key.  This is a
     * shortcut for the <code>UniqueConstraint</code> annotation at the table
     * level and is useful for when the unique key constraint
     * corresponds to only a single column. This constraint applies
     * in addition to any constraint entailed by primary key mapping and
     * to constraints specified at the table level.
     */
    boolean unique() default false;

    /**
     * (Optional) Whether the database column is nullable.
     */
    boolean nullable() default true;

    /**
     * (Optional) Whether the column is included in SQL INSERT
     * statements generated by the persistence provider.
     */
    boolean insertable() default true;

    /**
     * (Optional) Whether the column is included in SQL UPDATE
     * statements generated by the persistence provider.
     */
    boolean updatable() default true;

    /**
     * (Optional) The SQL fragment that is used when
     * generating the DDL for the column.
     * <p> Defaults to the generated SQL to create a
     * column of the inferred type.
     */
    String columnDefinition() default "";

    /**
     * (Optional) The name of the table that contains the column.
     * If absent the column is assumed to be in the primary table.
     */
    String table() default "";

    /**
     * (Optional) The column length. (Applies only if a
     * string-valued column is used.)
     */
    int length() default 255;

    /**
     * (Optional) The precision for a decimal (exact numeric)
     * column. (Applies only if a decimal column is used.)
     * Value must be set by developer if used when generating
     * the DDL for the column.
     */
    int precision() default 0;

    /**
     * (Optional) The scale for a decimal (exact numeric) column.
     * (Applies only if a decimal column is used.)
     */
    int scale() default 0;
}

 

 

你可以通过该注解修改列名,列字段大小,是否为空, unique( 唯一 ) ,允许它的值被更新、插入。

我们重新定义原来的 Book 实体

 

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	@Column(name = "book_title", nullable = false, updatable = false)
	private String title;
	private Float price;
	@Column(length = 2000)
	private String description;
	private String isbn;
	@Column(name = "nb_of_page", nullable = false)
	private Integer nbOfPage;
	private Boolean illustrations;
	
	// Constructors, getters, setters
}
 

BOOK DDL

 

CREATE TABLE `book` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `description` longtext,
  `illustrations` bit(1) DEFAULT NULL,
  `isbn` varchar(255) DEFAULT NULL,
  `nb_of_page` int(11) NOT NULL,
  `price` float DEFAULT NULL,
  `book_title` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) 

 

updatable insertable 默认值是true ,当他们的值是 false 时,产生的 SQL 语句将不包含相应的列。


八、 @Temporal


@javax.persistence.Temporal 注解用来表示时间日期,可以是 :DATE,TIME,TIMESTAMP.


看下例:

 

@Entity
public class Customer {
	@Id
	@GeneratedValue
	private Long id;
	private String firstName;
	private String lastName;
	private String email;
	private String phoneNumber;
	@Temporal(TemporalType.DATE)
	private Date dateOfBirth;
	@Temporal(TemporalType.TIMESTAMP)
	private Date creationDate;
	
	// Constructors, getters, setters
}

 

九、 @Transient


JPA 中,注解 @Entity 的类,所有的属性都会被自动映射到相应的表中。如果你不需映射类中的某个属性,可以使用 @javax.persistence.Transient 注解。

 

@Entity
public class Customer {
	@Id
	@GeneratedValue
	private Long id;
	private String firstName;
	private String lastName;
	private String email;
	private String phoneNumber;
	@Temporal(TemporalType.DATE)
	private Date dateOfBirth;
	@Transient
	private Integer age;
	@Temporal(TemporalType.TIMESTAMP)
	private Date creationDate;
	// Constructors, getters, setters
}

 

age 属性映射被忽略


十、 @Enumerated


我们看一下 CreditCardType 枚举类

 

public enum CreditCardType {
	VISA,
	MASTER_CARD,
	AMERICAN_EXPRESS
}

 

 

枚举类的值是常量,并且以声明的顺序赋予 int 值。编译时, VISA 赋予 0 MASTER_CARD 赋予 1 AMERICAN_EXPRESS 赋予 2. 持久化实现默认将枚举类型映射为 Integer

 

@Entity
@Table(name = "credit_card")
public class CreditCard {
	@Id
	private String number;
	private String expiryDate;
	private Integer controlNumber;
	private CreditCardType creditCardType;

	// Constructors, getters, setters
}

 

如果从中加入新的枚举常量,保存在数据库中的一些值将不再匹配枚举。一个好的办法是保存字符值,而不是顺序值。通过 @Enumerated(EnumType.STRING) ,顺序值 (ORDINAL 是默认值 )

 

@Entity
@Table(name = "credit_card")
public class CreditCard {
	@Id
	private String number;
	private String expiryDate;
	private Integer controlNumber;
	@Enumerated(EnumType.STRING)
	private CreditCardType creditCardType;
	// Constructors, getters, setters
}
 

 

十一、访问类型


到现在为止,我们标注类 (@Entity,@Table) 和属性 (@Basic,@Column,@Temporal ) ,我们将注解应用在字段上 (field access) 也可以注解在相应的属性上 (property access:getter method). 例:我们将注解 @Id 标注在 id 字段上,同样也可以标注在 getId() 的方法上。这很大程度上是个人偏好。我趋向于注解在属性上 ( 注解 getters) ,这样可以很容易阅读实体类拥有的字段。在这个教程里,为了可读性,我们把注解标注在字段上。


当我们把注解标注在字段上,实体类的访问类型就为字段类型,持久化实现将映射所有的字段 ( 没有标注 @Transient) 并将其持久化。

当我们把注解标注在属性 ( 注解 getters) 上,实体类的访问类型就为属性类型,持久化实现将映射所有的属性 ( 没有标注 @Transient) 并将其持久化。

如果没有通过显示指定访问类型,我们不能既标注字段又标注属性,否则会报错。


例:


标注字段:


@Entity
public class Customer {
	@Id
	@GeneratedValue
	private Long id;
	@Column(name = "first_name", nullable = false, length = 50)
	private String firstName;
	@Column(name = "last_name", nullable = false, length = 50)
	private String lastName;
	private String email;
	@Column(name = "phone_number", length = 15)
	private String phoneNumber;
	// Constructors, getters, setters
}
 


标注属性:

 

@Entity
public class Customer {
	private Long id;
	private String firstName;
	private String lastName;
	private String email;
	private String phoneNumber;

	// Constructors
	@Id
	@GeneratedValue
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Column(name = "first_name", nullable = false, length = 50)
	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	@Column(name = "last_name", nullable = false, length = 50)
	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Column(name = "phone_number", length = 15)
	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}
}

 

 

通过注解 @Access 可以指定标注类型,有 2 种参数值: AccessType.FIELD,AccessType.PROPERTY

 

@Entity
@Access(AccessType.FIELD)
public class Customer {
	@Id
	@GeneratedValue
	private Long id;
	@Column(name = "first_name", nullable = false, length = 50)
	private String firstName;
	@Column(name = "last_name", nullable = false, length = 50)
	private String lastName;
	private String email;
	@Column(name = "phone_number", length = 15)
	private String phoneNumber;

	// Constructors, getters, setters
	@Access(AccessType.PROPERTY)
	@Column(name = "phone_number", length = 555)
	public String getPhoneNumber() {
		return phoneNumber;
	}

	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}
}

 

 

标注在属性上的 @Access 将覆盖实体类级别的访问类型。所以最后 "phone_number" 的列上为 555(VARCHAR(555)).


十二、基本类型集合映射


JPA2.0 中, @ElementCollection 注解指定下列基本类型集合:

  1. java.util.Collection

  2. java.util.Set

  3. java.util.List


持久化实现默认会生成一个 " 实体类名 _ 集合属性名 " 的集合表来储存集合值。

我们可以通过 @CollectionTable 注解来修改集合表名,通过 @Column 来修改集合表列名字 ( 默认是 " 集合的属性名 ")


例:

 

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String title;
	private Float price;
	private String description;
	private String isbn;
	private Integer nbOfPage;
	private Boolean illustrations;
	@ElementCollection(fetch = FetchType.LAZY)
	@CollectionTable(name = "Tag")
	@Column(name = "Value")
	private List<String> tags = new ArrayList<String>();
	// Constructors, getters, setters
}

 

 

映射表:

 

 


 

十三、基本类型 Map 映射


JPA1.0 中, Map 映射中的 Keys 必须是基本类型, Values 必须是实体。现在,无论是 Keys 还是 Values 都可以包含基本数据类型,嵌入对象,和实体。


和基本类型集合映射一样,我们用 @ElementCollection 注解标注属性类型是 Map 类型。

通过 @CollectionTable 注解来修改 Map 表名 ( 默认是 " 实体类名 _Map 的属性名 ")

通过 @Column 来修改 Map value 列名字 ( 默认是 "Map 的属性名 ")

通过 @MapKeyColumn 来修改 Map key 列名字 ( 默认是 "Map 的属性名 _KEY")


例:

 

@Entity
public class CD {
	@Id
	@GeneratedValue
	private Long id;
	private String title;
	private Float price;
	private String description;
	@Lob
	private byte[] cover;
	@ElementCollection
	@CollectionTable(name = "track")
	@MapKeyColumn(name = "position")
	@Column(name = "title")
	private Map<Integer, String> tracks = new HashMap<Integer, String>();
	// Constructors, getters, setters
}

 

 

映射表:

 

  • 大小: 44.9 KB
  • 大小: 31.8 KB
  • 大小: 26.7 KB
0
0
分享到:
评论

相关推荐

    struts-2.3.1.2-part2.rar

    而Hibernate作为持久层框架,简化了数据库操作,提供了ORM(对象关系映射)功能。 SSH框架的整合使得开发者能够更有效地管理应用程序的各个层次,实现松耦合、高复用的设计。例如,通过Spring的DI,可以轻松地更换...

    Hibernate程序高手秘笈.part01-03.rar

    3. 实体类与对象关系映射:讲解如何定义Java实体类,并使用注解或XML文件进行对象关系映射,包括基本类型映射、关联映射(一对一、一对多、多对一、多对多)和继承映射。 4. Session与Transaction:介绍Hibernate的...

    ssm-spring-part.rar

    - **数据访问集成(Data Access/Integration)**:Spring提供了JDBC抽象层,简化了数据库操作,同时支持ORM(对象关系映射)框架如Hibernate和MyBatis。 - **MVC框架(Model-View-Controller)**:Spring MVC是...

    Hibernate程序高手秘笈.part07-09.rar

    这部分内容主要包含Part07和Part09两个部分,旨在帮助开发者提升在数据库操作和对象关系映射方面的技能。 Part07可能涉及的主题包括: 1. **持久化策略**:讲解了Hibernate的各种持久化策略,如懒加载(Lazy ...

    Linq-To-Sql-Part_2-Define-Data-Model-Class

    总结来说,“Linq-To-Sql-Part_2-Define-Data-Model-Class”这个主题将指导你如何使用LINQ to SQL创建数据模型类,理解对象关系映射原理,以及如何编写查询和管理数据库交互。了解这些知识点后,你可以更有效地在...

    Hibernate程序高手秘笈.part04-06.rar

    3. **映射文件详解**:详细讲解XML或注解方式的实体映射,包括属性映射、关系映射(一对一、一对多、多对多)、继承映射等。 4. **HQL(Hibernate Query Language)**: Hibernate自己的查询语言,类似于SQL,但更...

    Hibernate程序高手秘笈.part10-11.rar

    5. **多对多关系映射**:详述如何配置和处理多对多关联,包括中间表的管理,以及集合的懒加载和级联操作。 6. **一对一关系映射**:深入讨论一对一关系的配置,包括外键约束、主键共享以及一对一关系的级联操作。 ...

    XCP协议层标准ASAM_XCP_Part2-Protocol-Layer-Specification_V1-1-0

    本文件《ASAM_XCP_Part2-Protocol-Layer-Specification_V1-1-0》是ASAM XCP协议族中第二部分的内容,专注于协议层的规范说明。 XCP协议族是基于主从结构的通信协议,用于实现从主站(例如上位机软件或测试设备)对...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     B.2 运用反射机制来持久化Java对象 附录C 用XDoclet工具生成映射文件  C.1 创建带有@hibernate标记的Java源文件  C.2 建立项目的目录结构  C.3 运行XDoclet工具 附录D 发布和运行netstore应用  D.1 运行...

    extjs+struts+hibernate+spring(物流管理系统)-part3

    通过ORM(对象关系映射),它将Java对象映射到数据库表,使得开发者可以使用面向对象的方式来操作数据库。 - Spring:是Java企业级应用开发的核心框架,提供依赖注入、AOP(面向切面编程)、事务管理等功能,使得...

    hibernate-4.3.5(part1)

    Hibernate是一个流行的开源对象关系映射(ORM)框架,它允许Java开发者在处理数据库时使用面向对象的方式,极大地简化了数据库操作。在这个版本中,我们可能会发现一系列用于数据库交互的API、配置文件、示例代码和...

    Hibernate part 8:一对多关联关系映射

    在Java世界中,ORM(对象关系映射)框架如Hibernate极大地简化了数据库操作。本篇文章主要探讨的是Hibernate中的一对多关联关系映射,这是在实际项目开发中非常常见的一种关系映射类型。通过理解并掌握一对多关联,...

    hiberante4.2.3-part01

    Hibernate是Java领域中一款广泛应用的关系对象映射框架,它允许开发者使用面向对象的方式来操作数据库,大大简化了数据访问层的编码工作。这个压缩包“hibernate4.2.3-part01”很可能是Hibernate 4.2.3版本的一部分...

    hibernate-distribution-3.3.1.part4

    Hibernate是一个广泛使用的Java库,用于将对象关系映射(ORM)到关系数据库,简化数据库操作,让开发者可以使用面向对象的方式来处理数据库。 在Java世界中,ORM工具如Hibernate消除了手动编写SQL语句的需要,使得...

    Hiberante part 9:一对一关系映射

    Hibernate作为Java领域中最流行的ORM(对象关系映射)工具,它允许开发者以面向对象的方式处理数据库操作,简化了数据库与Java应用程序之间的交互。一对一关系映射是数据库设计中常见的一种关联类型,表示一个实体与...

    hibernate3.3.2jar包part1

    Hibernate,作为一个流行的开源对象关系映射(ORM)框架,为Java开发者提供了一种简单而强大的方式来管理数据库操作。在Java应用中,Hibernate使得开发人员可以将业务逻辑与数据库操作解耦,从而更加专注于应用程序...

Global site tag (gtag.js) - Google Analytics