ORM(Object Relational Mapping)是对象到关系的映射,它的作用是在关系数据库和对象之间做一个自动映射,将数据库中数据表映射成对象,也就是持久化类,对关系型数据以对象的形式进行操作,以减少应用开发的过程中数据持久化编程的任务。可以把ORM理解成关系数据库和对象的一个纽带。ORM原理如下图所示:
JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
在介绍newtouchOne框架中集成的JPA-ORM例子之前,我们先了解下何为实体(Entity), 按照JPA规范,具有ORM元数据的领域对象就叫做实体。它应具备以下条件:
1.必须使用javax.persistence.Entity注解或XML映射文件中有对应的<entity>元素;
2.必须具有一个不带参数的构造函数,类不能声明为final,方法和需要持久化的属性也不能声明为final;
3.如果游离态的实体对象需要以值的方式进行传递(如通过Session bean的远程业务接口传递),则必须实现Serializable接口;
4.需要持久化的属性,访问修饰符不能是public,它必须通过实体类方法进行访问。
下面详细介绍框架中采用XML映射文件形式配置元数据信息的过程:
(1)、编写实体类
编写的实体类用来描述数据库表的结构信息,所以类中属性应该和数据库中的字段相匹配,如下所示:
Person实体类:
Public class Person implements Entity<Long>{
private static final long serialVersionUID = 3070707016051870941L;
private Long id;
private String name;
private String gender;
private List<PersonEducation> personEducations;
…………………
}
PersonEducation实体类:
public class PersonEducation implements Entity<Long>{
private static final long serialVersionUID = 7349323599635279645L;
private Long id;
private String university;
private String major;
private String majorSubject;
private String diploma;
private Person person;
…………………
}
注:在上述的实体类中我们可以看到Person实体类中除了普通的属性外可以发现有一个对象形式的List,它的作用映射Person实体与PersonEducation实体间的关系,即一个Person可以对应多种Education,而在PersonEducation中声明了Person person,以此建立两者关系。如果多对多的关系的话,那么对应的实体类都应该是List形式表示,存放对方,如Teacher实体类中:private List<Student> students;Student实体类中:private List<Teacher> teachers;
(2)、XML映射文件
在此之前我们来先了解下XML映射文件中元数据描述信息注含义
Ø entity
当我们在<entity />节点中按”Alt+?”时,eclipse便会提示一些常用的描述信息供我们选择,如下所示:
注:
@access=”PROPERTY”:访问属性需要通过getter/setter方法
@cacheable=”true”:是否设置缓存
@metadata-complete=”true”:是否编译元数据
@name:entity的名称
Ø table
注:
@catalog:对应关系数据库中的catalog
@schema:对应关系数据库中的schema
Ø attributes属性
注:
@column-definition: 定义建表时创建此列的DDL
@precision:指定浮点型数据长度
@scale:小数长度
@fetch=”LAZY”: 加载方式lazy,也就是在实际使用到数据的时候才加载相关数据
@maps-id:关联集合的id
@target-entity:表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity
以下是实体Person、PersonEducation与数据表之间的映射关系:
<?xml version="1.0" encoding="utf-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<!-- 请勿随意修改! -->
<description>EDS ORM for MySQL</description>
<!—实体对象所在的包-->
<package>com.newtouch.model</package>
<!—实体类 -->
<entity class="com.newtouch.model.Person" name="Person">
<!—对应数据库表的名称 -->
<table name="TBL_PERSON" />
<attributes>
详见注:1)
<id name="id">
<column name="ID"/>
<generated-value strategy="IDENTITY" />
</id>
详见注:2)
<basic name="name">
<column name="NAME" length="255" nullable="false"/>
</basic>
<basic name="gender">
<column name="GENDER" length="10" nullable="false"/>
详见注:3)
<one-to-many name="personEducations" mapped-by="person"
fetch="LAZY" >
<cascade>
<cascade-all />
</cascade>
</one-to-many>
</attributes>
</entity>
<entity class="com.newtouch.model.PersonEducation" name="PersonEducation">
<table name="TBL_PERSON_EDUCATION" />
<attributes>
<id name="id">
<column name="ID" />
<generated-value strategy="IDENTITY" />
</id>
<basic name="university">
<column name="UNIVERSITY" length="20" nullable="false"/>
</basic>
<basic name="major">
<column name="MAJOR" length="20" nullable="false"/>
</basic>
<basic name="majorSubject">
<column name="MAJORSUBJECT" length="100" />
</basic>
<basic name="diploma">
<column name="DIPLOMA" length="20" />
</basic>
<many-to-one name="person">
<join-column name="PERSON_ID"
nullable="false"/>
</many-to-one>
</attributes>
</entity>
注:
1)、首先注意的是映射文件中以小写字母表示的属性对应实体类的属性名称,而大写表示的是数据库表的字段名称,如<id name="id">中id是实体中的属性名称,而<column name="ID" />中ID是对应数据库表的字段名,此外我们需要注意的是<generated-value strategy="IDENTITY" />,它的作用是给ID设置自增长策略,对于oracle是不支持的。
2)、普通属性用<basic/>描述,我们可以设置该字段的name、length、nullable、insertable、updateable等
3)、①对应实体间的关系我们可以分为one-to-one(Person-IDcard)、one-to-many(Person-Educations)、many-to-one(Educations- Person)、many-to-many(students-teachers),在上述例子中我们配置了Person-Educations的关系,我们应该注意的是谁是one谁是many,显然Person是one,所以在Person实体中我们使用的是< one-to-many/>,而PersonEducation中用的是<many-to-one/>.
②此外在PersonEducation中配置了<join-column name="PERSON_ID"/>,表明两个实体间的关系是通过PERSON_ID连接,对应到数据库表也就是主表和子表通过PERSON_ID连接。
③Person实体有时在操作数据时需要同步进行,也就是说删除一个人的信息,那么他的教育信息也没意义了,需要同步删除,此时级联操作就能保持数据操作的一致性,示例中的级联使用的是<cascade-all />,也就是说在Person进行save、update、delete操作时关联对象(PersonEducation)也会进行相同的操作。当然我们可以更明确的配置级联关系<cascade-refresh/>级联刷新、<cascade-persist/>级联保存、<cascade-remove/>级联删除