1 DB基本理论中的多表连接分类

1.1 笛卡尔积

  • 两个分别为n个字段和m个字段的表R和S的笛卡尔积是一个(m+n)字段的集合,即为R * S。若有k1条记录,S有k2条记录,则RS将有(k1k2)条记录。
  • 笛卡尔积查询:select * from R,S

1.2 条件连接

  • 从两个表的连接笛卡尔积中挑选出符合连接条件的部分记录的集合。当条件为两个字段的等值比较时,称之为等值连接。
  • select * from R,S where C=E

1.3 内连接

  • 与条件连接功能相同,只不过,语法不同。
  • select * from R inner join S on C=E
  • inner可省略:select * from R join S on C=E

1.4 左外连接

  • 若是R左外连接S,则保留R表中所有记录,连接结果集中字段值可能为NULL。
  • select * from R left outer join S on R.B = S.B
  • 其中outer可省略,select * from R left join S on R.B = S.B

1.5 右外连接

  • 若是R右外连接S,则保留S表中的所有记录,连接结果集中R表中字段值可能为NULL。
  • select * from R right outer join S on R.B = S.B
  • 其中outer可省略,select * from R right join S on R.B = S.B

2 Hibernate支持的多表连接类型

  • 注意,“迫切”是fetch的音译,与迫切无关
  • 以下程序均以1:n关联关系的Country和Minister为例,DB中具有如下数据:

2.1 左外连接HQL实现

  • 左外连接的查询结果为List,其泛型为Object[]。每个List元素,即每个Object[],均包含两个数组元素:数组的第一个元素为查询出的Country对象。数组的第二个元素为该Country对象集合元素中的一个元素,即查询出的Minister对象。若Country对象的集合属性中包含多个Minister对象,则会生成多个Object[]元素。
  • List元素的个数,等于查询出的每个Country对象所包含的集合元素的和。即,若查询出3个Country对象,第一个Country中包含了2个Minister,第二个Country中包含1个Minister,第三个Country中包含了3个MInister,则List元素的个数为2+1+3=6个。而这6个对象分别为:
  • 本例在定义实体时一定注意,在Country类中的toString()方法中对其关联属性ministers进行输出。但是在Minister类的toString()方法中不要再对其关联属性country进行输出。因为双方均进行关联属性输出,在这里会抛出StackOverflowError错误。
	 //左外连接的对象为Country的ministers属性
	String hql = "from Country c left outer join c.ministers";
	//左外连接的查询结果为List,但其泛型为Object[]
	//数组的第一个元素为查询出的Country数据,已经封装为了Country对象
 //数组的第二个元素为查询出的Minister数据,已经封装为了Minister对象
	List<Object[]> list = session.createQuery(hql).list();
	for(Object[] objects: list) {
		System.out.println(objects[0] + ":" + objects[1]);
	}

2.2 迫切左外连接HQL实现

  • 迫切左外连接的查询结果为List,但是其泛型为Country。即系统已将查询数据进行了自动封装。不过,其List元素个数仍为查询出的每个Country对象所包含的集合元素的和,而非Country对象的个数,即List元素会出现重复现象。
//迫切左外连接,语法上就是多了个fetch
			String hql = "from Country c left outer join fetch c.ministers";
			//左外连接的查询结果为List,但是其泛型为Country,即系统已将查询数据进行自动封装。
			//并且还将查询出Minister对象也封装相应的Country中。
			List<Country> list = session.createQuery(hql).list();
			for(Country country: list) {
				System.out.println(country);
			}

  • 查看其结果,发现数据重复:该主加载对象有几个关联对象,结果就会重复几次,所以需要对结果去重。

2.3 迫切左外连接HQL实现(去重)

  • 去重使用关键字distinct。
//就增加了一个distinct进行去重操作
			String hql = "select distinct c from Country c left outer join fetch c.ministers";
			List<Country> list = session.createQuery(hql).list();
			for(Country country: list) {
				System.out.println(country);
			}

2.4 左外连接去重的QBC实现

			//指定Country要与其关联属性Ministers进行左外连接,并对结果去重
			List<Country> list = session.createCriteria(Country.class)
			.createCriteria("ministers", JoinType.LEFT_OUTER_JOIN)
			.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
			for(Country country : list) {
				System.out.println(country);
			}