第5章Hibernate的基本用法 5.7映射组件属性

来源:互联网 发布:桌面desktop.ini 知乎 编辑:程序博客网 时间:2024/04/28 19:54

5.7 映射组件属性

映射组件属性的意思是:持久化类的属性并不是基本数据类型,也不是字符串、日期等标量类型的变量,而是一个符合类型的对象,在持久化的过程中,它仅仅被当做值类型,而并非引用另一个持久化实体。

为了映射组件属性,Hibernate提供了<component.../>元素,每个<component.../>元素映射一个组件属性。使用<component.../>元素映射组件属性时需要指定一个name属性,用于指定该组件属性的名称。除此之外,使用<component.../>元素还需要如下几个可选属性。

属性备注class指定组件类的类名insert指定被映射的字段是否出现在SQL的insert语句中update指定被映射的字段是否出现在SQL的update语句中access指定Hibernate访问该组件属性的访问策略,默认是propertylazy设置该组件是否在持久化对象第一次被访问时启用延迟加载,该属性默认是trueoptimistic-lock设置更新该组件属性是否需要获取乐观锁unique指定是否在该组件映射的所有字段上添加唯一性约束
为<component../>元素添加<property.../>子元素来映射组件属性的子属性。

添加<parent.../>子元素用于映射组件类内一个指向其容器实体的引用。定义<parent.../>子元素时只需一个name属性,其值为引用容器实体的属性名。

除此之外,<component.../>元素内还可出现如下几种子元素:

*<component.../>:该组件属性里的属性是一个组件类型。

*集合映射元素:如果组件类型里的属性是数组类型、集合类型等

*关联映射元素:如果组件属性里的属性是另外一个持久化实例的引用

例子:

1)Person.java

<span style="font-size:18px;">public class Person{//标识属性private Integer id;//普通属性ageprivate int age;//组件属性nameprivate Name name;//...//name属性的setter和getter方法public void setName(Name name){this.name = name;}public Name getName(){return this.name;}}</span>

2)Name.java

<span style="font-size:18px;">public class Name{//定义first属性private String first;//定义last属性private String last;//引用拥有该Name的Person对象private Person owner;//无参数的构造器public Name(){}//初始化first、last属性的构造器public Name(String first , String last){this.first = first;this.last = last;}//...//owner属性的setter和getter方法public void setOwner(Person owner){this.owner = owner;}public Person getOwner(){return this.owner;}}</span>
3)Person.hbm.xml

<span style="font-size:18px;"><?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 映射标识属性 --><id name="id" column="person_id"><!-- 指定主键生成器策略 --><generator class="identity"/></id><!-- 映射普通属性 --><property name="age" type="int"/><!-- 映射组件属性name,组件属性的类型为Name --><component name="name" class="Name" unique="true"><!-- 指定owner属性代表容器实体 --><parent name="owner"/><!-- 映射组件属性的first属性 --><property name="first"/><!-- 映射组件属性的last属性 --><property name="last"/></component></class></hibernate-mapping></span>
4)PersonManager.java

<span style="font-size:18px;">private void createAndStorePerson(){Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction();//创建Person对象Person yeeku = new Person();//为Person对象设置属性yeeku.setAge(29);Name n = new Name("crazyit.org" , "疯狂Java联盟");yeeku.setName(n);session.save(yeeku);tx.commit();HibernateUtil.closeSession();}</span>
对于这种只包含基本类型、字符串、日期类型等属性的组件,Hibernate将会把每个属性映射成一个数据列——即<component.../>元素里每个<property.../>子元素映射一个数据列。

5.7.1 组件属性为集合

如果组件类再次包括了List、Set、Map等集合属性,则我们可以在<component.../>元素里使用<list.../>、<set.../>和<map.../>子元素来映射这些集合元素。

例子:

1)Name.java

public class Name{//定义first属性private String first;//定义last属性private String last;//引用拥有该Name的Person对象private Person owner;private Map<String ,Integer> power= new HashMap<String ,Integer>();//...//owner属性的setter和getter方法public void setOwner(Person owner){this.owner = owner;}public Person getOwner(){return this.owner;}//power属性的setter和getter方法public void setPower(Map<String ,Integer> power){this.power = power;}public Map<String ,Integer> getPower(){return this.power;}}
2)Person.hbm.xml

<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 映射标识属性 --><id name="id" column="person_id"><!-- 指定主键生成器策略 --><generator class="identity"/></id><!-- 映射普通属性 --><property name="age" type="int"/><!-- 映射组件属性name,组件属性的类型为Name --><component name="name" class="Name" unique="true"><!-- 指定owner属性代表容器实体 --><parent name="owner"/><!-- 映射组件属性的first属性 --><property name="first"/><!-- 映射组件属性的last属性 --><property name="last"/><!-- 映射组件属性里的Map集合属性 --><map name="power" table="name_power"><!-- 映射集合属性数据表的外键列 --><key column="person_name_id" not-null="true"/><!-- 映射集合属性数据表的Map key列 --><map-key column="name_aspect" type="string"/><!-- 映射保存集合元素的数据列 --><element column="name_power" type="int"/></map></component></class></hibernate-mapping>
当主程序保存了这样的Person对象后,Hibernate依然将Name组件的各属性映射成不同的数据列,再将Name里的Map属性映射到另一个数据表。

5.7.2 集合属性的元素为组件

映射集合属性时依然使用<list.../>、<set.../>和<map.../>等元素,只是不再使用<element.../>元素来映射集合元素,而是用<composite-element.../>元素来映射集合元素。

配置<composite-element.../>元素时需要指定一个class属性,其值指定了集合里组件对象的类型。

例子:

1)Person.java

public class Person{//标识属性private Integer id;//普通属性ageprivate int age;//组件属性nameprivate Map<String , Name> nicks= new HashMap<String , Name>();//...//nicks属性的setter和getter方法public void setNicks(Map<String , Name> nicks){this.nicks = nicks;}public Map<String , Name> getNicks(){return this.nicks;}}
2)Person.hbm.xml

<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 映射标识属性 --><id name="id" column="person_id"><!-- 指定主键生成器策略 --><generator class="identity"/></id><!-- 映射普通属性 --><property name="age" type="int"/><!-- 映射nicks集合属性,集合属性对应的数据表为nick_inf --><map name="nicks" table="nick_inf"><!-- 映射集合属性数据表的外键列 --><key column="person_id" not-null="true"/><!-- 映射集合属性数据表的Map key列 --><map-key column="phase" type="string"/><!-- 映射保存集合里的组件元素 --><composite-element class="Name"><!-- 指定owner属性代表容器实体 --><parent name="owner"/><!-- 映射组件属性的first属性 --><property name="first"/><!-- 映射组件属性的last属性 --><property name="last"/></composite-element></map></class></hibernate-mapping>
对于这种集合元素是组件的情形,Hibernate依然会把组件的各属性映射到不同的数据列,只是这些数据列将保存在集合属性列中。
5.7.3 组件作为Map的索引

Hibernate使用<composite-map-key.../>元素来映射符合类型的key,定义<composite-map-key.../>元素时需要指定一个class属性,其值为Map key的类名。

由于Map key的特殊性,所以程序必须重写该组件类的equals()和hashCode()两个方法。

1)Person.java

public class Person{//标识属性private Integer id;//普通属性ageprivate int age;//集合属性nickPowerprivate Map<Name , Integer> nickPower= new HashMap<Name , Integer>();//...//nickPower属性的setter和getter方法public void setNickPower(Map<Name , Integer> nickPower){this.nickPower = nickPower;}public Map<Name , Integer> getNickPower(){return this.nickPower;}}
2)Name.java

public class Name{//定义first属性private String first;//定义last属性private String last;//引用拥有该Name的Person对象private Person owner;//...//owner属性的setter和getter方法public void setOwner(Person owner){this.owner = owner;}public Person getOwner(){return this.owner;}//重写equals方法,根据first、last进行判断public boolean equals(Object obj){if (this == obj){return true;}if (obj != null && obj.getClass() == Name.class){Name target = (Name)obj;if (target.getFirst().equals(getFirst())&& target.getLast().equals(getLast())){return true;}}return false;}//重写hashCode方法,根据first、last计算hashCode值public int hashCode(){return getFirst().hashCode() * 13 + getLast().hashCode();}}
3)Person.hbm.xml

<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 映射标识属性 --><id name="id" column="person_id"><!-- 指定主键生成器策略 --><generator class="identity"/></id><!-- 映射普通属性 --><property name="age" type="int"/><!-- 映射nickPower集合属性,集合属性对应的数据表为nick_power --><map name="nickPower" table="nick_power"><!-- 映射集合属性数据表的外键列 --><key column="person_id" not-null="true"/><!-- 映射集合属性数据表的Map key列 ,因为Map key的数据类型是复合类型,所以使用如下元素--><composite-map-key class="Name"><!-- 映射复合组件的属性 --><key-property name="first" type="string"/><key-property name="last" type="string"/></composite-map-key><!-- 映射集合元素的数据列 --><element column="nick_power" type="int"/></map></class></hibernate-mapping>
Name组件的各属性被映射到集合属性表里的数据列,且此时Name属性作为Map key使用,因此Hibernate会将外键列、Name属性所映射的多列作为联合主键。

5.7.4 组件作为复合主键

使用组件作为复合主键,也就是使用组件作为持久化类的标识符,则该组件类必须满足以下要求:

*必须实现java.io.Serializable接口

*建议正确地重写equals()和hashCode()方法,也就是根据组件类的关键属性来区分组件对象

Hibernate使用<composite-id.../>元素来映射这种复合主键,在<composite-id.../>元素里使用<key-property.../>元素来映射组件类的各属性。

例子:

1)Person.java

public class Person{//以Name组件作为标识属性private Name name;//普通属性ageprivate int age;//name属性的setter和getter方法public void setName(Name name){this.name = name;}public Name getName(){return this.name;}//..}
2)Name.java

public class Nameimplements java.io.Serializable{//定义first属性private String first;//定义last属性private String last;//无参数的构造器public Name(){}//初始化全部属性的构造器public Name(String first , String last){this.first = first;this.last = last;}//...//重写equals方法,根据first、last进行判断public boolean equals(Object obj){if (this == obj){return true;}if (obj != null && obj.getClass() == Name.class){Name target = (Name)obj;if (target.getFirst().equals(getFirst())&& target.getLast().equals(getLast())){return true;}}return false;}//重写hashCode方法,根据first、last计算hashCode值public int hashCode(){return getFirst().hashCode() * 7 + getLast().hashCode();}}
3)Person.hbm.xml

<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 映射组件类型的标识属性 --><composite-id name="name" class="Name"><!-- 映射组件主键里的各属性 --><key-property name="first" type="string"/><key-property name="last" type="string"/></composite-id><!-- 映射普通属性 --><property name="age" type="int"/></class></hibernate-mapping>
4)PersonManager.java

private void createAndStorePerson(){Session session = HibernateUtil.currentSession();Transaction tx = session.beginTransaction();//创建Person对象Person yeeku = new Person();//为Person对象设置属性yeeku.setAge(29);//创建一个Name对象作为Person对象的标识属性值Name n = new Name("crazyit.org" , "疯狂Java联盟");yeeku.setName(n);session.save(yeeku);tx.commit();HibernateUtil.closeSession();}
程序运行结束后,Hibernate将会把Name组件所映射的多个数据列作为联合主键。

5.7.5 多列作为联合主键

Hibernate允许直接将持久化类的多列映射成联合主键。如果需要直接将持久化类的多列映射成联合主键,则该持久化类必须满足如下两个条件:

1、实现java.io.Serializable接口

2、建议根据联合主键列所映射的属性来重写equals()和hashCode()方法。

例子:

1)Person.java

public class Personimplements java.io.Serializable{//定义first属性,作为标识属性的成员private String first;//定义last属性,作为标识属性的成员private String last;//普通属性ageprivate int age;//...//重写equals方法,根据first、last进行判断public boolean equals(Object obj){if (this == obj){return true;}if (obj != null && obj.getClass() == Person.class){Person target = (Person)obj;if (target.getFirst().equals(getFirst())&& target.getLast().equals(getLast())){return true;}}return false;}//重写hashCode方法,根据first、last计算hashCode值public int hashCode(){return getFirst().hashCode() * 13+ getLast().hashCode();}}

如需映射first和last两个标识属性,同样使用<composite-id.../>元素,此时的<composite-id.../>元素不需要name和class属性。

2)Person.hbm.xml
<?xml version="1.0" encoding="GBK"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="org.crazyit.app.domain"><class name="Person" table="person_inf"><!-- 直接使用composite-id映射多列联合主键 --><composite-id><!-- 映射组件主键里的各属性 --><key-property name="first" type="string"/><key-property name="last" type="string"/></composite-id><!-- 映射普通属性 --><property name="age" type="int"/></class></hibernate-mapping>


0 0
原创粉丝点击