hibernate QBC和QBE精讲与案列分析(中)

16、Not equal

ne(String?propertyName, Object?value)

neProperty(String?propertyName, String?otherPropertyName)

From Object o where o.property not

17、查询条件逻辑非

not(Criterion?expression)

From Object o where not(一个查询条件)

18、查询条件逻辑and

运算

or(Criterion?lhs, Criterion?rhs)

From Object o where o.property1 =? or o.property2=?

  

  具体各种方法的使用例子,请看8.3节。

Example类

  使用Example类进行查询,首先需要创建一个对象样板,然后检索出所有与这个样板对象相同的对象。如,

  BasicCar bc=new BasicCar();

  bc.setFactory("aaaa");

  

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add(Example.create(bc));

  

  List results = crit.list();

  Example使用静态方法create(Object entity)来创建一个Criterion对象,它按照对象的属性来比较查询条件,以上的程序段检索factory属性为"aaaa"的BasicCar对象。

  另外,Example也提供了给这个样板对象设置一些查询过滤。例如,

  Example exampleUser =Example.create(bc)

  .ignoreCase() //忽略大小写

  .enableLike(MatchMode.ANYWHERE); //任意位置的匹配

  

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add(exampleUser);

  List results = crit.list();

  这个查询相当于查询factory属性为"�aa%",即只要对factory属性值进行aaaa的模糊字符串匹配。

  Example类提供的各种进行查询过滤的方法如下。

● enableLike(MatchMode):用于过滤string匹配,有4个选择。分别为MatchMode.ANYWHERE(默认匹配模式,表示任意位置的匹配,形如%value%)、MatchMode.END(表示匹配结尾,形如%value)、MatchMode.EXACT(表示完全匹配)、MatchMode.START (表示匹配开头,形如value%)。

● excludeNone():排除为null或0的属性值匹配。

● excludeProperty(String name):排除名字为name的属性的匹配。

● excludeZeroes():排除为0的属性值匹配。

● ignoreCase():匹配String时忽略大小写。

● setEscapeCharacter(Character escapeCharacter):对like从句的字符串匹配,排除某些字符。

● setPropertySelector(Example.PropertySelector selector):选择属性的匹配策略。

  这些过滤方法都是返回Example类,所以可以连接着设置各种过滤。

8.1.3  使用QBC各种检索例子

  下面将通过具体的例子来介绍,如何使用Criteria查询,结合各种Criterion查询条件和Projection投影运算,满足各种数据检索要求。

  1.返回所有的对象

  下面是一个最简单的Criteria查询,只是在创建Criteria时制定检索的对象,不设置任何查询条件,即返回的List为所有的BasicCar对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  List results = crit.list();

  返回的List中存放的是BasicCar对象。

  以上的代码相当于执行了select * from basiccar。

  2. 聚集函数

Criteria使用Projections类可以使用聚集函数max、min、avg、count、sum、countDistinct、rowCount等。

org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用 setProjection()应用投影到一个查询。

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.rowCount() )
    .add( Restrictions.eq("color", Color.BLACK) )
    .list();

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount() )
        .add( Projections.avg("weight") )
        .add( Projections.max("weight") )
        .add( Projections.groupProperty("color") )
    )
    .list();

 

  如果需要使用多个Projections设置多个条件,则需要使用Projections的projectionList()函数创建一个ProjectList。

  下面的例子Projections的max、min、countDistinct返回BasicCar的最大id、最小日期和计算不同的名字有多少个。

  Criteria crit = session.createCriteria(BasicCar.class)

  ProjectionList projList = Projections.projectionList();

  projList.add(Projections.max("id"));

  projList.add(Projections.min("date"));

  projList.add(Projections.countDistinct("name"));

  crit.setProjection(projList);

  List results = crit.list();

  返回的List中存放有最大id,最小日期,不同name的个数,这三者组成的对象数组。

  其对应的SQL语句如下:

  select max(this_.id) as y0_, min(this_.date) as y1_, count(distinct this_.name) as y2_ from basiccar this_

  3. many-to-one双向关联检索

  检索sid=1的Salesman对象关联的carorder对象cid大于1的数据

  Criteria crit = session.createCriteria(Salesman.class);

  .add(Restrictions.eq("sid",new Long(1)))

  .createCriteria("carorders")

  .add(Restrictions.gt("cid",new Long(1)))

  .list();

  返回的List中存放的是Salesman对象。

  如果使用了连接检索策略,以上查询相当于执行以下的SQL语句:

  select * from salesman this_ inner join carorder1 carorder1_ on this_.sid=carorder1_.salesId left outer join salesman salesman4_ on carorder1_.salesId=salesman4_.sid where this_.sid=? and carorder1_.cid>?

  4.使用数学运算符>=、>、!=、=

  下面的例子检索日期大于等于"1994-03-04"的BasicCar对象,并且使用setMaxResults(1)函数设置返回的列表只取一个结果。

     Criteria crit = session.createCriteria(BasicCar.class);

   crit.add( Expression.ge("date", Date.valueOf("1994-03-04")) );

   crit.setMaxResults(1);

 

   List results = crit.list();

  其对应的SQL语句如下:

  select *  from basiccar b where b.date>='1994-03-04'

  下面的例子检索id大于1的BasicCar对象。

     Criteria crit = session.createCriteria(BasicCar.class);

   crit.add( Expression.gt("id", new Long(1)) );

   List results = crit.list();

  其对应的SQL语句如下:

  select *  from basiccar b where b.id>1

  下面的例子检索id不等于1的BasicCar对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add( Expression.ne("id", new Long(1)) );

  List results = crit.list();

  其对应的SQL语句如下:

  select *  from basiccar b where b.id<>1

  5. 查询id

  下面的例子检索主键为1的对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add( Expression idEq(new Long(1)) );

  crit.setMaxResults(1);

  List results = crit.list();

  其对应的SQL语句如下:

  select *  from basiccar b where b.id = 1

  6. group by

  下面的例子按name来进行分组。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.setProjection(Projections.groupProperty("name"));

  List results = crit.list();

  返回对象List用来存放不同名字的数组,存放的是string行的name。

  其对应的SQL语句如下:

  select b.name from basiccar b group by b.name

  7. 字符串匹配,like和islike

  下面的例子使用like()函数检索name开头字母为A的BasicCar对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add(Restrictions.like("name","A%"));

  List results = crit.list();

  其对应的SQL语句如下:

  select * from basiccar b where b.name like ‘A%’

  使用islike()函数,代表不区分大小写的字符串匹配。

  MatchMode可以选择匹配模式,MatchMode.END从末端开始匹配,MatchMode.ANYWHERE表示任意地方的字符串匹配, MatchMode.START从开始的地方开始匹配, MatchMode.EXACT表示整个字符串精确匹配。

  下面的例子检索数据库name的后面字符为不区分大小写的a的BasicCar对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add(Restrictions.islike("name","a", MatchMode.END));

  List results = crit.list();

  8. is null

  下面的例子检索数据库name为空的BasicCar对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.add(Restrictions.isNull("name"));

  List results = crit.list();

  9. 投影某些属性

  使用Projections.property()函数,可以对结果进行某些属性的投影,相当于使用select语句。

  下面的例子返回结果进行name和date列的投影。

  Criteria crit = session.createCriteria(BasicCar.class);

  ProjectionList projList = Projections.projectionList();

  projList.add(Projections.property("name"));

  projList.add(Projections.property("date"));

  crit.setProjection(projList);

  List results = crit.list();

  返回的List中存放的是由name和date组成的对象数组。

  其对应的SQL语句如下:

  select b.name as n, b.date as d from basiccar b

  10. 计算列返回的数目

  下面的例子计算返回的BasicCar对象的数量。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.setProjection(Projections.rowCount());

  List results = crit.list();

  其对应的SQL语句如下:

  select count(*) as y0_ from basiccar this_

  11. 设置返回结果

  下面的例子使用setFirstResult(2)设置从第二个开始返回,使用setMaxResults(2)设置每次最多返回2个对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.setFirstResult(2);

  crit.setMaxResults(2);

  List results = crit.list();

  下面的例子使用uniqueResult得到单个对象。

  Criteria crit = session.createCriteria(BasicCar.class);

  Criterion price = Restrictions.gt("name",new Lone(1));

  crit.setMaxResults(1);

  Product product = (Product) crit.uniqueResult();

  12. 结果排序

  使用Order类调用desc()函数、asc()函数可以进行排序。

  下面的例子根据BasicCar对象的name进行升序排序。

  Criteria crit = session.createCriteria(BasicCar.class);

  crit.addOrder(Order.desc("name"));

  对应的SQL语句是:

  Select * from basiccar b by b.name desc

  13. 逻辑or、and条件

  下面的例子中设置了3个条件,分别是id大于等于1,name开头字母为P,factory的开头字母为f。然后把前两个条件进行逻辑或操作,即只要满足其中之一,再把最后一个条件进行逻辑与操作。

  Criteria crit = session.createCriteria(BasicCar.class);

  Criterion id = Restrictions.gt("id",new Long(1));

  Criterion name = Restrictions.like("name","P%");

  LogicalExpression orExp = Restrictions.or(id,name);

  crit.add(orExp);

  crit.add(Restrictions.ilike("factory","f%"));

  List results = crit.list();

  在上面的例子中Restrictions.or()把id和name两个检索条件进行or结合;在原来的查询条件上不断地add(),那么就相当于把检索条件进行and逻辑与操作。

  其对应的SQL语句如下:

select * from basiccar this_ where (this_.id>? or this_.name like ?) and lower(this_.factory) like ?

 

16.1. 创建一个Criteria 实例

org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。

Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();

16.2. 限制结果集内容

一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。org.hibernate.criterion.Restrictions类 定义了获得某些内置Criterion类型的工厂方法。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .add( Restrictions.between("weight", minWeight, maxWeight) )
    .list();

约束可以按逻辑分组。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .add( Restrictions.or(
        Restrictions.eq( "age", new Integer(0) ),
        Restrictions.isNull("age")
    ) )
    .list();

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
    .add( Restrictions.disjunction()
        .add( Restrictions.isNull("age") )
     .add( Restrictions.eq("age", new Integer(0) ) )
     .add( Restrictions.eq("age", new Integer(1) ) )
     .add( Restrictions.eq("age", new Integer(2) ) )
    ) )
    .list();

Hibernate提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许你直接使用SQL。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
    .list();

{alias}占位符应当被替换为被查询实体的列别名。

Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个Property

Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.disjunction()
        .add( age.isNull() )
     .add( age.eq( new Integer(0) ) )
     .add( age.eq( new Integer(1) ) )
     .add( age.eq( new Integer(2) ) )
    ) )
    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
    .list();

16.3. 结果集排序

你可以使用org.hibernate.criterion.Order来为查询结果排序。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "F%")
    .addOrder( Order.asc("name") )
    .addOrder( Order.desc("age") )
    .setMaxResults(50)
    .list();

List cats = sess.createCriteria(Cat.class)
    .add( Property.forName("name").like("F%") )
    .addOrder( Property.forName("name").asc() )
    .addOrder( Property.forName("age").desc() )
    .setMaxResults(50)
    .list();

16.4. 关联

你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "F%")
    .createCriteria("kittens")
        .add( Restrictions.like("name", "F%")
    .list();

注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。

接下来,替换形态在某些情况下也是很有用的。

List cats = sess.createCriteria(Cat.class)
    .createAlias("kittens", "kt")
    .createAlias("mate", "mt")
    .add( Restrictions.eqProperty("kt.name", "mt.name") )
    .list();

(createAlias()并不创建一个新的 Criteria实例。)

Cat实例所保存的之前两次查询所返回的kittens集合是 没有被条件预过滤的。

List cats = sess.createCriteria(Cat.class)
    .createCriteria("kittens", "kt")
        .add( Restrictions.eq("name", "F%") )
    .returnMaps()
    .list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
    Map map = (Map) iter.next();
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
    Cat kitten = (Cat) map.get("kt");
}

16.5. 动态关联抓取

你可以使用setFetchMode()在运行时定义动态关联抓取的语义。

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.EAGER)
    .setFetchMode("kittens", FetchMode.EAGER)
    .list();

这个查询可以通过外连接抓取matekittens。 查看第 20.1 节 “ 抓取策略(Fetching strategies) ”可以获得更多信息。

16.6. 查询示例

org.hibernate.criterion.Example类允许你通过一个给定实例 构建一个条件查询。

Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .list();

版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。

你可以自行调整Example使之更实用。

Example example = Example.create(cat)
    .excludeZeroes()           //exclude zero valued properties
    .excludeProperty("color")  //exclude the property named "color"
    .ignoreCase()              //perform case insensitive string comparisons
    .enableLike();             //use like for string comparisons
List results = session.createCriteria(Cat.class)
    .add(example)
    .list();

你甚至可以使用examples在关联对象上放置条件。

List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .createCriteria("mate")
        .add( Example.create( cat.getMate() ) )
    .list();

16.7. 投影(Projections)、聚合(aggregation)和分组(grouping)

org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用 setProjection()应用投影到一个查询。

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.rowCount() )
    .add( Restrictions.eq("color", Color.BLACK) )
    .list();

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount() )
        .add( Projections.avg("weight") )
        .add( Projections.max("weight") )
        .add( Projections.groupProperty("color") )
    )
    .list();

在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他们也出现在SQL的group by子句中。

你可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的实现方式:

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
    .addOrder( Order.asc("colr") )
    .list();

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.groupProperty("color").as("colr") )
    .addOrder( Order.asc("colr") )
    .list();

alias()as()方法简便的将一个投影实例包装到另外一个 别名的Projection实例中。简而言之,当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount(), "catCountByColor" )
        .add( Projections.avg("weight"), "avgWeight" )
        .add( Projections.max("weight"), "maxWeight" )
        .add( Projections.groupProperty("color"), "color" )
    )
    .addOrder( Order.desc("catCountByColor") )
    .addOrder( Order.desc("avgWeight") )
    .list();

List results = session.createCriteria(Domestic.class, "cat")
    .createAlias("kittens", "kit")
    .setProjection( Projections.projectionList()
        .add( Projections.property("cat.name"), "catName" )
        .add( Projections.property("kit.name"), "kitName" )
    )
    .addOrder( Order.asc("catName") )
    .addOrder( Order.asc("kitName") )
    .list();

你也可以使用Property.forName()来表示投影:

List results = session.createCriteria(Cat.class)
    .setProjection( Property.forName("name") )
    .add( Property.forName("color").eq(Color.BLACK) )
    .list();

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount().as("catCountByColor") )
        .add( Property.forName("weight").avg().as("avgWeight") )
        .add( Property.forName("weight").max().as("maxWeight") )
        .add( Property.forName("color").group().as("color" )
    )
    .addOrder( Order.desc("catCountByColor") )
    .addOrder( Order.desc("avgWeight") )
    .list();

16.8. 离线(detached)查询和子查询

DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的 Session来执行它。

DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
    .add( Property.forName("sex").eq('F') );
    
Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();

DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者Property获得。

DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
 .setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
 .add( Property.forName("weight).gt(avgWeight) )
 .list();

DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
 .setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
 .add( Subqueries.geAll("weight", weights) )
 .list();

甚至相互关联的子查询也是有可能的:

DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
 .setProjection( Property.forName("weight").avg() )
 .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class, "cat")
 .add( Property.forName("weight).gt(avgWeightForSex) )
 .list();

 

8.2  连 接 查 询

  在数据库检索过程中,表之间的连接查询是很常见,先来看一下各种连接的定义。

8.2.1  连接定义

  本节将介绍三种连接方式,分别是内连接、右外连接和左外连接。

● 左连接:左连接的结果集包括LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表的列均为空值。

● 右连接:右连接是左连接的反向连接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。

● 内连接:内连接使用比较运算符根据每个表共有的列的值匹配两个表中的行,即返回相关联的列所匹配的行。

  下面用具体实例来说明这三种连接。

  数据库中有两个表,person和basiccar,其中person的列carId是关联basiccar的外键,现在表中的数据如下:

  basiccar表

  +----+------+----------+------------+

  | id | name | factory  | date         |

  +----+------+----------+------------+

  |  1 | car1 | shenzhen | 1992-02-02 |

  |  2 | car2 | nanjing  | 1992-04-02  |

  +----+------+----------+------------+

  person表

  +----+-----------+-------+

  | id | salesname  | carId |

  +----+-----------+-------+

  |  1 | man1        |     1  |

  |  2 | man2        |  NULL |

  |  3 | man3        |     1  |

  +----+-----------+-------+

  

  

  由上面的数据可以看出,basiccar表有2组数据;person表有3组数据。其中存在两组关联:id为1的person和id为1的basiccar关联;id为3的person和id为1的basiccar关联。下面,分别来看看各种连接下,数据的检索结果。

  1.内连接

  在数据库中输入以下查询语句:

  select person.id as pid, 

         basiccar.id as bid, 

         person.carid as carid, 

         person.salesname as sName,

         basiccar.name as carName, 

         basiccar.factory factory, 

         basiccar.date as date 

  from person person inner join basiccar basiccar

  on person.carId=basiccar.id;

  数据查询结果如下:

  +-----+-----+------+-------+--------+----------+------------+

  | pid | bid | carid | sName | carName | factory  | date       |

  +-----+-----+------+-------+---------+----------+-----------+

  |   1 |   1  |     1 | man1  | car1    | shenzhen | 1992-02-02 |

  |   3 |   1  |     1 | man3  | car1    | shenzhen | 1992-02-02 |

  +-----+-----+------+-------+---------+----------+-----------+

  由上面的查询结果可以看出,内连接检索出有关联关系的两组对象组成的数据,内连接是把关联关系返回。

  2.左连接

  先看使用person表左连接basiccar表的查询结果。在数据库中输入以下查询语句:

  select person.id as pid, 

         basiccar.id as bid, 

         person.carid as carid, 

         person.salesname as sName, 

         basiccar.name as carName, 

         basiccar.factory factory, 

         basiccar.date as date 

  from person person left join basiccar basiccar 

  on person.carId=basiccar.id;

  数据查询结果如下:

  

  +-----+-----+-------+-------+---------+----------+----------+

  | pid | bid  | carid | sName | carName | factory  | date       |

  +-----+------+-------+-------+---------+----------+---------+

  |   1 |    1  |     1  | man1  | car1    | shenzhen  | 1992-02-02 |

  |   2 | NULL |  NULL | man2  | NULL    | NULL       | NULL        |

  |   3 |    1  |     1  | man3  | car1    | shenzhen  | 1992-02-02 |

  +-----+------+-------+-------+---------+----------+---------+

  由上面的查询结果可以看出,person表的3组数据都被检索出来了,与其相关联的basiccar数据,如果有值,则把关联的basiccar记录检索出来;如果为空,则赋值null。

  下面再看一下使用basiccar表左连接person表的查询结果。在数据库中输入以下查询语句:

  select person.id as pid, 

         basiccar.id as bid, 

         person.carid as carid, 

         person.salesname as sName, 

         basiccar.name as carName, 

         basiccar.factory factory, 

         basiccar.date as date 

  from basiccar basiccar left join person person 

  on person.carId=basiccar.id;

  数据查询结果如下:

  +------+-----+-------+-------+---------+----------+---------+

  | pid  | bid | carid | sName | carName | factory  | date       |

  +------+-----+-------+-------+---------+----------+---------+

  |    1  |   1 |     1  | man1  | car1    | shenzhen | 1992-02-02 |

  |    3  |   1 |     1  | man3  | car1    | shenzhen | 1992-02-02 |

  | NULL |   2 |  NULL | NULL  | car2    | nanjing   | 1992-04-02 |

  +------+-----+-------+-------+---------+----------+---------+

  由上面的查询结果可以看出,basiccar表的两组数据都被检索出来了,与其相关联的person数据,如果为空,则赋值null。在上表结果中,由于basiccar.id=1的basiccar记录关联两组person记录(id=1,id=3),所以会把这两组组合作为两个记录返回;basiccar.id=2的basiccar记录,虽然没有关联的person记录,则把person记录记为null,也把其作为一个记录返回。

  由此可见,左连接是内连接的检索结果加上左连接左边表中没有关联关系的数据。

  3.右连接

  先看一下使用person表右连接basiccar表的查询结果。在数据库中输入以下查询语句:

  select person.id as pid, 

         basiccar.id as bid, 

         person.carid as carid, 

         person.salesname as sName, 

         basiccar.name as carName, 

         basiccar.factory factory, 

         basiccar.date as date 

  from person person right join basiccar basiccar 

  on person.carId=basiccar.id;

  数据查询结果如下:

  +------+-----+-------+-------+---------+---------+----------+

  | pid  | bid | carid | sName | carName | factory  | date       |

  +------+-----+-------+-------+---------+---------+----------+

  |    1 |   1 |     1 | man1  | car1    | shenzhen | 1992-02-02 |

  |    3  |   1 |     1  | man3  | car1    | shenzhen | 1992-02-02 |

  | NULL |   2 |  NULL | NULL  | car2    | nanjing   | 1992-04-02 |

  +------+-----+-------+-------+---------+---------+----------+

  由上面的查询结果可以看出,person表右连接basiccar表的查询结果与basiccar表左连接person表的查询结果一样。basiccar表的两组数据都被检索出来了,与其相关联的person数据,如果为空,则赋值null。在上表结果中,由于basiccar.id=1的basiccar记录关联两组person记录(id=1,id=3),所以会把这两组组合作为两个记录返回;basiccar.id=2的basiccar记录,虽然没有关联的person记录,则把person记录记为null,也把其作为一个记录返回。

  再看一下使用basiccar表右连接person表的查询结果。在数据库中输入以下查询语句:

  select person.id as pid, 

         basiccar.id as bid, 

         person.carid as carid, 

         person.salesname as sName, 

         basiccar.name as carName, 

         basiccar.factory factory, 

         basiccar.date as date 

  from basiccar basiccar right join person person 

  on person.carId=basiccar.id;

  数据查询结果如下:

  +-----+------+-------+-------+---------+---------+----------+

  | pid | bid  | carid | sName | carName | factory  | date       |

  +-----+------+-------+-------+---------+---------+----------+

  |   1 |    1  |     1  | man1  | car1    | shenzhen | 1992-02-02 |

  |   2 | NULL |  NULL | man2  | NULL    | NULL      | NULL         |

  |   3 |    1  |     1  | man3  | car1    | shenzhen | 1992-02-02 |

  +-----+------+-------+-------+---------+---------+----------+

  由上面的查询结果可以看出,basiccar表右连接person表的查询结果与person表左连接basiccar表的查询结果一样。person表的3组数据都被检索出来了,与其相关联的basiccar数据,如果有值,则把关联的basiccar记录检索出来;如果为空,则赋值null。

  由此可见,右连接是内连接的检索结果加上右连接右边表中没有关联关系的数据。

8.2.2  Hql,Criteria对连接的支持

  分别在数据库中建立两张关联的salesman表和carorder1表,其中carorder1表使用salesId列关联到salesman。

  其中,salesman表及其数据如下:

  +-----+-----------+

  | sid | salesName |

  +-----+-----------+

  |   1 | man32      |

  +-----+-----------+

  carorder1表及其数据如下:

  +-----+-------------+---------+

  | cid | carname      | salesId |

  +-----+-------------+---------+

  |   1 | order212122  |       1  |

  |   2 | order2221    |       1  |

  +-----+-------------+---------+

  使用多对一双向关联来建立它们的对象关系模型。如果两个对象模型之间没有设立关联关系,虽然数据库表中有关联关系,也无法通过Hibernate 的Hql和Criteria进行连接查询,因为这两个查询是面向对象的,必须是对象之间建立了关联关系。如果是两个对象间没有关系的表进行连接查询,那么可以使用SQL查询,这样可以使用on来指定进行任意列的关联。下面是两个表对应的Salesman对象和CarOrder对象的主要部分。

  Salesman对象的代码:

  public class Salesman implements java.io.Serializable{

   private long sid; 

  

   private String salesName;

  

   private Set carOrders = new HashSet();

  //…省略了getter/setter和构造函数

  

  Salesman对象的映射文件Salesman.hbm.xml的主要部分,定义了salesman的属性和数据库表映射,以及关联到carorder的集合映射。代码如下:

  <class name="basicCar.bean.Salesman" table="salesman" lazy="false">

     <id column="sid" name="sid" type="long">

     <generator class="increment"></generator>

     </id>

     <property name="salesname" column="salesName" type="string"></property>

     <set name="carorders" inverse="false" cascade="delete">

     <key column="salesId"/>

     <one-to-many class="basicCar.bean.CarOrder"/>

     </set>

    </class>

  CarOrder对象的代码:

  public class CarOrder  implements java.io.Serializable {

   private long cid; 

   private String carName;

   private Salesman salesman;

  //…省略了getter/setter和构造函数

  CarOrder对象的映射文件CarOrder.hbm.xml的主要部分,定义了carorder的属性和数据库表映射关系,以及和salesman对象的关联。

  <class name="basicCar.bean.CarOrder" table="carorder1" lazy="false">

     <id column="cid" name="cid" type="long">

     <generator class="increment"></generator>

     </id>

     <property name="carname"  column="carname" type="string"></property>

     <many-to-one name="salesman" 

      column="salesId" 

      class="basicCar.bean.Salesman" 

      cascade="all"

      not-null="false">

     </many-to-one>

    </class>

 

分享: 

猜你喜欢

转载自blog.csdn.net/zxssoft/article/details/83055105