欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hibernate 5.3(三)

程序员文章站 2022-05-13 20:02:03
...

映射组件属性

映射组件属性定义

组件属性,看到组件,你肯定就会想到是由一系列东西组成的东西,才可以称之为组件吧。

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

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

  • class: 指定组件类的类名。如果不指定该属性,Hibernate将通过反射来得到该组件的类型。
  • insert:指定被映射的字段是否出现在SQL的insert语句中。
  • update:指定被映射的字段是否出现在SQL的update语句中。
  • access : 指定Hibernate访问该组件属性的访问策略,默认是property。
  • lazy: 设置该组件是否在持久化对象第–次被访问时启用延迟加载,该属性默认是true。
  • optimistic-ock: 设置更新该组件属性是否需要获取乐观锁,如果该属性设置为true,则当修改该组件属性时,持久化对象的版本号会增加。
  • unique:指定是否在该组件映射的所有字段上添加唯一性约束。(对应到数据库,就是创建了一个索引)

一个 自定义类通常还包括其他属性,因此还应该为<componen…/>兀素增加<property…>子兀素来映射组件属性的子属性。此处的<property…> 子元素与<las…/元素里<property…>子元素的用法完全相似,因此当组件类型的属性是基本数据类型、String 类型、 日期类型时,使用<property…/> 元索进行映射。

使用注意

<component…/>: 如果该组件属性里的属性不是基本类型、String 类型、日期类型等, 而是另一个组件类型时,则在<componet…/> 里再次使用<component…>子元素进行映射。

集合映射元素:如果组件类型里的属性是数组类型、集合类型等,则可以在<componet…/>里使用<se…/>、<lis…/>. <map…/>等子元素来映射这些集合属性。

关联映射元素: 如果组件属性里的属性是另外一个持久化实例的引用,还可以在<component…/>里使用<many-to-one…/>、<one-to-one…/>等 子元素,这就变成Hibernate关联映射。

对于组件属性,Hibernate 组件里的每一个属性添加一个数据列即可。

使用例子
public class Person {
	private Integer id;
	private Integer age;
	private Name name;

	public Name getName() {
		return name;
	}

	public void setName(Name name) {
		this.name = name;
	}

	public Integer getId() {
		return id;
	}

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

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}

public class Name {
	private String first;
	private String last;
	private Person p;// 引用该name的Person 对象

	public Person getP() {
		return p;
	}

	public void setP(Person p) {
		this.p = p;
	}

	public String getFirst() {
		return first;
	}

	public void setFirst(String first) {
		this.first = first;
	}

	public String getLast() {
		return last;
	}

	public void setLast(String last) {
		this.last = last;
	}

}

     <component name="name" class="Name" unique="true" ><!-- name是对应POJO 的属性名 ,class是指定的组件的POJO类-->
     <parent name="p"></parent><!-- parent 是指定引用该容器实体的对象的属性 ,保证该标签是在<property>之前,否则会报错-->
    <property name="first"></property>
    <property name="last"></property>
    </component>

组件属性为集合

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

在原先的NAME POJO基础上,添加如下内容:

private Map<String, Integer> map = new java.util.HashMap<String, Integer>();

	public Map<String, Integer> getMap() {
		return map;
	}

	public void setMap(Map<String, Integer> map) {
		this.map = map;
	}
<component name="name" class="Name" unique="true" ><!-- name是对应POJO 的属性名 ,class是指定的组件的POJO类 -->
    <parent name="p"></parent><!-- parent 是指定引用该容器实体的对象的属性 ,保证该标签是在<property>之前,否则会报错 -->
    <property name="first"></property>
    <property name="last"></property>
    <map name="map" table="NAME_ADD">
      <key column="id" not-null="true"></key>
      <map-key type="string" column="name_number"></map-key>
      <element type="integer" column="name_number1"></element>
    </map>
    </component>

上面的配置文件中可以看出,该<map…/>元素的配置方法与前面映射集合属性时所用的<map…/>元素没有任何区别。没错!实际上就是没有任何区别,只是之前把<map…/>作为<class…>的子元素使用,现在把<map…/>作为<component…/>的子元素而已。

集合属性元素是组件

集合除了可以存放基本类型、字符串、日期类型之外,还可以存放组件对象(也就是复合类型)。实际上, 在更多情况下,集合里存放的都是组件对象。对于这种持久化类的映射稍有不同,我们映射集合属性时依然使用<ist…/>. <se…>和<map…/>等元素,只是不再使用<element…/>元素来映射集合元素, 而是用<composite-elemen…/>元素来映射集合元素。

配置<composite-elemen…/>元素时需要指定-一个class属性,其值指定了集合里组件对象的类型。由于<composite-elemen…/>元素映射的是集合里的组件(还是组件),所以<composite-element…/>元素和<component…>元素的用法非常相似。

如果集合组件的属性是基本类型、字符串和日期等类型,使用<property…> 子元素映射这些属性即可。
如果集合组件的属性又是组件类型,则使用<nested-composite-element…/>元素映射这些嵌套组件属性。
如果集合组件的属性引用其他持久化实体,则应该使用<many-to-one…/>元素来映射该属性。

与<component…>元素类似的是,<composite-elemen…> 元素也可接受一~个<parent…/> 子元素,用于引用包含该组件属性的持久化实体。

Hibermate为了简化管理,不再允许在<composite-element…/>元素里使用<list…>.<set…>. <map…/>等 集合映射元素!否则将形成无尽循环:集合里的元素是组件类型,而组件类型的属性再次是集合,集合又可包含组件类型…这势必导致映射关系无限复杂。(你记住只有在集合的属性是组件,才涉及到使用<composite-element…/>,一定要有集合,才会使用到composite,千万不要乱

使用例子

在原来Person POJO 基础上添加:

private Map<String,Name> nicks = new java.util.HashMap<String, Name>();
	public Map<String, Name> getNicks() {
		return nicks;
	}

	public void setNicks(Map<String, Name> nicks) {
		this.nicks = nicks;
	}

	public Name getName() {
		return name;
	}

<map name="nicks" table="NICKS">
       <key column="id" not-null="true"></key>
       <map-key type="string" > </map-key>
       <composite-element class="Name"><!-- 注意这里的map的value 是复杂类型 ,需要指定相应的class,即组件的类型 -->
       <parent name="p"/>
       <property name="first" type="string"></property><!-- 组件中的属性是基本属性,还是用property 标签 -->
       <property name ="last" type = "string"></property>
       </composite-element>
   </map>

可以看出只是原来使用<element…>元素映射Map集合的value,而现在使用<composite-element…>元素映射Map集合的value 因为此时的value的类型是Name。

组件作为Map的索引

由于Map集合的特殊性,它允许使用复合类型的对象作为Map的key。

Hibermate使用

在<composite-map-key…/>元素里可以出现如下两种子元素:

  • <key-property…/>:当组件里的属性是基本类型、字符串和日期类型时,这些属性即可。
  • <key-many-to-one…>:当组件里的属性是对其他持久化实体的引用时,则使用该元素来映射这些属性,这也是一种特殊的关联映射。

使用例子

在原先的Person POJO 添加如下:

private Map<Name,Integer> nickspower = new java.util.HashMap<Name, Integer>();
	
	public Map<Name, Integer> getNickspower() {
		return nickspower;
	}

	public void setNickspower(Map<Name, Integer> nickspower) {
		this.nickspower = nickspower;
	}

自定义Key对象需要重写对象的equals和hashcode,同时该类还需要实现序列化接口。

@Override
	public boolean equals(java.lang.Object obj) {
		// TODO Auto-generated method stub
		if(this==obj){
			return true;
		}
		if(obj!=null&&obj.getClass()==Name.class){
			Name  target = (Name)obj;
			if(target.first==first&&target.last==last){
				return true;
			}
		}
		return false;//如果if中,都不执行,需要这里指定一个返回值。
	}
	
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.first.hashCode()*13+this.last.hashCode();
	}
	
<map name="nickspower" table="NICKPOWER"><--NICKPOWER 这张表的主键是由id、first和last 组成-->
   <key column="id" not-null="true"></key>
    <composite-map-key class="Name">
        <key-property name="first" type="string"></key-property>
        <key-property name="last" type="string"></key-property>
    </composite-map-key>
    <element column="nickpower_value" type="integer"></element>
   </map>
Map<String, Name>  map= new java.util.HashMap<String,Name>();
		   	map.put("liu", n);
		   	map.put("new", n);
		   	p.setNicks(map);
		   	Map<Name, Integer> map1 = new java.util.HashMap<Name, Integer>();
		   	map1.put(n, 12);
		   	map1.put(n, 13);
		   	p.setNickspower(map1);
		   	ss.save(p);

组件作为复合主键

如果数据库采用简单的逻辑主键,则不会出现组件类型的主键。但在一.些特殊的情况下,总会出现组件类型主键, Hibernate也为这种组件类型的主键提供了支持。

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

  • 必须实现java.io.Serializable接口。
  • 必须正确地重写equals()和hashCode()方法,也就是根据组件类的关键属性来区分组件对象。

当使用组件作为复合主键时,Hibemate无法为这种复合主键自动生成主键值,所以程序必须为持久化实例分配这种组件标识符。(所以你在映射文件也没有必要添加标签)

在<composite-id…>元素里使用<key-propery…/>元素来映射组件类的各属性。

使用例子:

public class Name implements java.io.Serializable {
	private String first;
	private String last;

	@Override
	public boolean equals(java.lang.Object obj) {
		// TODO Auto-generated method stub
		if (this == obj) {
			return true;
		}
		if (obj != null && obj.getClass() == Name.class) {
			Name target = (Name) obj;
			if (target.first == first && target.last == last) {
				return true;
			}
		}
		return false;// 如果if中,都不执行,需要这里指定一个返回值。
	}

	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.first.hashCode() * 13 + this.last.hashCode();
	}

	public String getFirst() {
		return first;
	}

	public void setFirst(String first) {
		this.first = first;
	}

	public String getLast() {
		return last;
	}

	public void setLast(String last) {
		this.last = last;
	}

}

<class name="Student" table="student">
 <composite-id class="Name" name="name"><!-- 这里是复合主键,需要指定复合类 -->
  <key-property name="first" type="string"></key-property>
  <key-property name = "last" type="string"></key-property>
 </composite-id>
 <property name="age" type="integer"></property>
</class>
	        Student s = new Student();
		   Name n = new Name();
		   n.setFirst("sss");
		   n.setLast("jjj");
		   s.setAge(11);
		   s.setName(n);
		   ss.save(s);

多列作为联合主键

Hibernate还提供了另-一种联合主键支持,Hibemate 允许直接将持久化类的多列映射成联合主键。如果需要直接将持久化类的多列映射成联合主键,则该持久化类必须满足如下两个条件:

  • 实现java.io.Serializable接口。
  • 根据联合主键列所映射的属性来重写equals()和hashCode()方法。

使用例子:

public class Student implements java.io.Serializable {
	private String first;
	private String last;
	private Integer age;

	public String getFirst() {
		return first;
	}

	public void setFirst(String first) {
		this.first = first;
	}

	public String getLast() {
		return last;
	}

	public void setLast(String last) {
		this.last = last;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}

<class name="Student" table="student">
 <composite-id >
  <key-property name="first" type="string"></key-property>
  <key-property name = "last" type="string"></key-property>
 </composite-id>
 <property name="age" type="integer"></property>
</class>
		Student s = new Student();Student s = new Student();
		   s.setFirst("sss");
		   s.setLast("jjj");
		   s.setAge(11);
		   ss.save(s);

映射first 和last 两个标识属性,同样使用<composite-d…/>元素,此时的<composite-d…/>元素不需要name和class属性,因为标识属性没有实现类,所以不需要class属性; 因为不是一个真实存在的属性,所以不需要name属性。