Hibernate学习笔记(五)映射组件属性

  • 组件属性为集合
  • 集合属性的元素为组件
  • 组件作为map的索引
  • 组件作为复合主键
  • 多列作为联合主键


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

如下实例:
组件属性无法用元素来映射(如上面的name属性)。上面的Name类中包含一个owner属性,该owner属性指向包含该Name属性的容器实体(也就是Person对象)。
1、为了映射组件属性,需要使用元素。下面介绍元素常见的一下属性:
name:指定该组件属性的名称。
class:指定组件类的类名。可以不指定,不指定的话,Hibernate通过反射来得到该组件的类型。
insert:指定被映射的字段是否出现在SQL的insert语句中。
update:指定被映射的字段是否出现在SQL的update语句中。
access:指定Hibernate访问该组件属性的访问策略,默认是property。
lazy:设置该组件是否在持久化对象第一次被访问时启用延迟加载,默认是true。
optimistic-lock:设置更新该组件属性是否需要获取乐观锁,如果该属性设置为true,则当修改该组件属性时,持久化对象的版本号会增加。
unique:指定是否在该组件映射的所有字段上添加唯一性约束。

2、元素的子元素:
:这里的子元素与元素下的子元素用法完全相似。
:用于映射组件类内一个指向其容器实体的引用,该元素只有一个name属性,其值为引用容器实体的属性名。
:如果组件属性仍然是组件,则在元素里再次使用子元素进行映射。
集合映射元素:如果组件类型里的属性时数组类型,集合类型等,可以在里使用等子元素来映射这些集合属性。
关联映射元素:如果组件属性里的属性时另外一个持久化实例的应用,还可以在里使用等子元素,这就变成了Hibernate关联映射中的一种特例了。

3、对于只包含普通标量属性的组件类型而言,Hibernate的处理策略非常简单,组件里每个属性映射一个数据列即可。

组件属性为集合:
组件属性为集合,上篇文章中介绍集合属性的映射配置是一样的,没有任何区别。


集合属性的元素为组件:
集合中除了可以存放基本类型、字符串、日期类型外,还能存放组件对象(也就是符合类型)。和映射集合属性类似,只是将元素下的子元素改为子元素。需要指定一个class属性,值为集合里组建对象的类型。
元素和元素用法非常相似:
如果组件的属性是基本类型、字符串和日期类型,使用子元素映射这些属性。
如果组件的属性又是组件类型,则使用元素映射这些嵌套组件属性。
如果组件的属性引用其他持久化实体,则应使用元素来映射该属性。
元素也可以接受子元素来引用包含该组件属性的持久化实体。
注意:Hibernate不允许元素里再使用集合映射,如等集合映射,否则映射关系无线复杂。

组件作为map的索引:
1、Map集合可以允许使用复合类型对象作为Map的key值,Hibernate使用来映射符合类型的key(回忆以下:基础类型的key使用来映射的)。元素需要class属性来表示key的类名。

2、可以下列两个子元素:
:当组件里的属性是基本类型、字符串、日期类型时,使用该元素来映射这些属性即可。
:当组件里的属性时对其他持久化实体的引用时,则使用该元素来映射这些属性,这也是一种关联映射。

3、元素的子元素可视为一种特殊的元素,它一样可以接受name、access、type、column、length等属性,这些属性的作用和元素中的完全一样。

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

示例如下:
POJO类:
public class Person {

	private int id;
	private int age;
	//组件的属性为集合,Name类中有Map power,power属性为Map集合
	private Name name;
	//集合属性元素为组件
	private List nicks = new ArrayList();
	//组件作为Map的索引
	private Map nickPower = new HashMap();
	//省略getter 和 setter方法
}
相关的Java Bean类:
public class Name {

	private String first;
	private String last;
	private Person owner;
	private Map power = new HashMap();
	public Name(String string, String string2) {
		this.first=string;
		this.last = string2;
	}
	public Name() {
	}
	//省略getter 和 setter方法
}

public class Name2 {

	private String nickname;
	//省略getter setter 带参数和无参数的构造方法
	
	//重写equals方法,根据first、last进行判断
		public boolean equals(Object obj)
		{
			if (this == obj)
			{
				return true;
			}
			if (obj != null 
				&& obj.getClass() == Name2.class)
			{
				Name2 target = (Name2)obj;
				if (target.getNickname().equals(getNickname()))
				{
					return true;
				}
			}
			return false;
		}

		//重写hashCode方法,根据first、last计算hashCode值
		public int hashCode()
		{
			return getNickname().hashCode() * 13;
		}
}

映射文件(Person.hbm.xml):

	
		
			
		
		
		
		 
			
			
			
			
				
				
				 
			
		
		
		
			
			
			
				
				
			
		
		
		
			
			
				
			
			
		
	

测试类为:
public class PersonManager {
	public static void main(String[] args) {
		Session sess = MyHibernateUtil.currSession();
		Transaction tx = sess.beginTransaction();
		Person rmd = new Person();
		Name name = new Name();
		name.setFirst("first1");
		name.setLast("last2");
		Map power = new HashMap();
		power.put("key", 12);
		name.setPower(power);
		rmd.setName(name);
		rmd.setAge(26);
		Name2 n1 = new Name2("n1");
		Name2 n2 = new Name2("n2");
		List list = new ArrayList();
		list.add(n1);
		list.add(n2);
		rmd.setNicks(list);
		
		Map nickPower = new HashMap();
		nickPower.put(n1, 100);
		rmd.setNickPower(nickPower);
//		Person rmd = (Person) sess.get(Person.class, 1);
//		System.out.println(rmd.getNickPower().get(new Name2("n1")));
		sess.save(rmd);


测试结果为:
INFO: HHH000232: Schema update complete
Hibernate: /* insert org.crazyit.app.domain.Person */ insert into person_inf (age, first, last) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.name.power */ insert into name_power (person_name_id, name_aspect, name_power) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.nicks */ insert into person_nick (person, person_nick_id, nickname) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.nicks */ insert into person_nick (person, person_nick_id, nickname) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.nickPower */ insert into person_nickPower (person_name_id, nickname, name_power) values (?, ?, ?)
Hibernate学习笔记(五)映射组件属性_第1张图片
从图中我们可以看到创建第一张表”person_inf“时,使用Person中的常规数据类型的属性(id,age)和属性为组件的属性(Name组件中的first last)作为列建表和存储数据。
当持久化类为集合属性,且集合元素为组件时,如Person中的List集合nicks中放的元素是Name2,和之前集合映射一样,都另外新建一个表,此处建的表是图中的表二”person_nick“,person_nick_id列是映射List集合的序号,person是对应person的序号,nickname为Name2中定义的属性对应的列。
第三张表”person_nickPower“分别是对应person的序号,value对应的值,key对应的对象。我们在测试类中打开注释的代码,允许结果如下:
INFO: HHH000232: Schema update complete
Hibernate: select person0_.person_id as person_i1_1_0_, person0_.age as age2_1_0_, person0_.first as first3_1_0_, person0_.last as last4_1_0_ from person_inf person0_ where person0_.person_id=?
Hibernate: select nickpower0_.person_name_id as person_n1_1_0_, nickpower0_.name_power as name_pow2_3_0_, nickpower0_.nickname as nickname3_0_ from person_nickPower nickpower0_ where nickpower0_.person_name_id=?
100
如果我们不重写Name2类中的equals和hashCode方法的话,java是无法知道new Name2("n1")和Map中的key n1是相同的对象,则无法取出value的值,显示输出内容为null
第四张表”name_power“是因为由于我们在Name类中定义了Map属性的power,所以在映射的时候,建立新表了。我们使用下列代码可以输出map中的value值为12:
//		Person rmd = (Person) sess.get(Person.class, 1);
//		System.out.println(rmd.getName().getOwner().getAge());


组件作为复合主键:
1、使用组件作为数据库主键,需要满足下列两个要求:
必须实现java.io.Serizlizable接口。
必须正确地重写equals()和hashCode()方法,也就是根据组件累的关键属性来区分组件对象。
在Hibernate3中,第二个要求并不是必须的,但最好这样做。因为这样做能从Java语义上更好地区分两个标识属性值,这样Hibernate能将他们当作两条记录的主键。

2、使用来映射这种复合主键,需要指定name和class,仍然可以指定access、 unsave-value等可选属性。

3、在元素里使用元素来映射组件类的个属性。注意:不支持在元素里使用子元素。

示例如下:我们在POJO Person类中定义name组件为主键
public class Person {

	private Name name;
	private int age;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Name getName() {
		return name;
	}
	public void setName(Name name) {
		this.name = name;
	}
}
要求Name必须实现Serializable接口,且实现equals和hashCode方法
public class Name implements Serializable{

	private String first;
	private String last;
	public Name(String string, String string2) {
		this.first=string;
		this.last = string2;
	}
	public Name() {
	}
	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;
	}
	//重写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();
		}
}
映射主键是,如果主键是组件的话,使用composite-id代替id元素,使用key-property映射组件中的基础属性

	
		
			
			
		
		
	
测试类:
public class PersonManager {
	public static void main(String[] args) {
		Session sess = MyHibernateUtil.currSession();
		Transaction tx = sess.beginTransaction();
		Person rmd = new Person();
		Name name = new Name();
		name.setFirst("first1");
		name.setLast("last2");
		rmd.setName(name);
		rmd.setAge(26);
		sess.save(rmd);
		tx.commit();
		MyHibernateUtil.closeSession();
	}
}
测试类允许后,生成表,如果所示,
Hibernate学习笔记(五)映射组件属性_第2张图片


多列作为联合主键:
和上面组件作为复合主键相似,只是去掉元素中的name和class属性。
public class Person implements Serializable{

	//private Name name;
	private int age;
	private String first;
	private String last;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = 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;
	}
	//重写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();
			}
}

	
		
			
			
		
		
	

需要持久化类实现Serializable接口并重写equals和hashCode方法,去掉composite-id的name和class属性。




你可能感兴趣的:(学习笔记之Hibernate)