现在的位置: 首页 > 综合 > 正文

集合的映射

2013年01月19日 ⁄ 综合 ⁄ 共 5051字 ⁄ 字号 评论关闭

1 set映射  

建表user(id,name)id是主键,email(id ,email)id,email为复合主键,两张表外键关联,email不需要生成持久化类,只要在user的持久化类中定义一个set集合来装email

user的映射文件如下:

<set name="emails" table="email">
   <key column="id"></key>
   <element type="string" column="email"></element>
 </set>

当使用的是自定义的类时很像组成关系,映射文件的范例如下:

<set name="emails" table="email">
   <key column="id"></key>
   <composite-element class="tie.Email">
   <property name="email" type="string" column="email"></property>
   </composite-element>
</set>

当然还要重写email类的equals和hashcode方法

   public boolean equals(Object other) {
         if ( (this == other ) ) return true;
   if ( (other == null ) ) return false;
   if ( !(other instanceof Email) ) return false;
   Email castOther = ( Email ) other;
        
   return (this.getId()==castOther.getId())
 && ( (this.getEmail()==castOther.getEmail()) || ( this.getEmail()!=null && castOther.getEmail()!=null && this.getEmail().equals(castOther.getEmail()) ) );
   }
  
   public int hashCode() {
         int result = 17;
         result = 37 * result + (int) this.getId();
         result = 37 * result + ( getEmail() == null ? 0 : this.getEmail().hashCode() );
         return result;
   }  

2 List映射

  建表user(id,name)id是主键,email(id ,email,pos)没有主键,两张表外键关联,其他的和set映射很像。 

user的映射文件如下:

<list name="emails" table="email">
   <key column="id"></key>
   <index column="pos"></index>
   <element type="string" column="email"></element>
 </list

 

 3 map映射

建表user(id,name)id是主键,email(id ,email,email_alias)不设主键,两张表外键关联,其他的和set映射很像。

user的映射文件如下:

  <map name="emails" table="email">
   <key column="id"></key>
   <index column="email_alias" type="string"></index>
   <element type="string" column="email"></element>
  </map>

4 bag映射

bag是hibernate特有的类型,和set类似但是允许重复。类user里用list类型实现:private List emails;

建表同map。user的映射文件如下:

   <bag name="emails" table="email">
   <key column="id"></key>
   <element type="string" column="email"></element>
   </bag>

这种方式效率低下因为在做删除操作时由于可以重复,它会把记录全部删除后再进行插入。为了弥补这个hibernate做了一个扩展,设计了idbag,但是他要求在数据库中的email表加入一个字段c_id

user的映射文件如下:

<idbag name="emails" table="email">
   <collection-id type="string" column="c_id">
   <generator class="uuid.hex"></generator>
   </collection-id>
   <key column="id"></key>
   <element type="string" column="email"></element>
</idbag>

排序:

排序有两种:一种是内存排序一种是数据库排序

有执行排序的位置,可以分为内存排序和数据库排序,
1.内存排序,通过提供一个实现了Comparator接口的排序器来实现
配置文件:
<set name="emails" table="email" sort="org.tie.TieComparator">
   <key column="id"></key>
   <element type="string" column="email"></element>
  </set>

public class TieComparator implements Comparator {

 public int compare(Object o1, Object o2) {
  // TODO Auto-generated method stub
  String s1 = (String)o1;
  String s2 = (String)o2;
  return s1.compareTo(s2) * -1;
 }

}

2.数据库排序,就是执行sql语句的时候利用order by {数据库字段1 数据库字段2...} {asc, desc}来达到目的
配置文件:
<set name="children" order-by="DISPLAY_POSITION desc">

注意:order-by属性完全是sql的语法,比如:字段名士数据库字段名称,不是hql中映射的名称,而且可以提供多个排序字段,默认排序方式是asc(升序)

 set,map支持数据库排序和内存排序,list都不支持,bag,idbag只支持数据库排序

 补充值类型和实体类型:

Hibernate 中的查询参数主要有两种类型:值类型和实体类型,值类型就是指一个切实的值 ( String int List 这些 ) ,实体类型就是一个具体的实体,如编写的 User Organization 等,值类型的查询和普通 sql 几乎一样,而实体类型的查询就体现了 Hibernate 的强项, ^_^ ,可以起到简化 sql 的作用,并且使得查询语句更加容易理解。

          值类型

1.      简单值

举例如下:

from User u where u.name=:username and u.yearold=:yearold

这就是一个常见的简单值的占位符式的查询,通过这样的方式就可以把值注入到参数中:

query.setParameter(“username”,”bluedavy”);

query.setParameter(“yearold”,25);

同样, hibernate 也支持和 sql 完全相同的 ? 的方式,那么上面的语句以及注入参数的方式就变为了:

from User u where u.name=? and u.yearold=?

query.setParameter(0,”bluedavy”);

query.setParameter(1,25);

推荐使用第一种,那样参数的意义更容易被理解。

2.      in 查询

in 查询也是经常被使用到的一种查询,在 Hibernate 中表现出来会稍有不同,不过如果按照对象观点去看就很容易理解了,例如下面这句:

from User u where u.name in (:usernameList)

Hibernate 中通过这样的方式将值注入到这个参数中:

List list=new ArrayList();

list.add(“jerry”);

list.add(“bluedavy”);

query.setParameterList(“usernameList”,list);

sql 中通常是组装一个由 , 连接的值来构成 in 中的参数值,而在 Hibernate 中则依照对象转化为采用 list 了, ^_^ ,是不是更方便些。

2.           实体类型

Hibernate中关联采用的都是对象形式,表现对外就是隐藏了数据库的外键的部分,这也就对习惯使用sql查询的人带来一个问题,因为无法再操作外键字段,那么在涉及到关联的实体的查询时应该怎么做呢,我把它分为单实体和实体集合两种情况来说说。

1.      单实体

单实体的查询对应到 sql 情况通常是在一对多的情况下通过多端查询同时结合一端的一些过滤条件,在 sql 中通常采用 join 的方式来实现这个,而在 Hibernate 中要实现这点就更容易了,举例如下:

User Organization 是一对多,现在要查询属于组织机构名称为 ”Blogjava” 以及用户年龄大于 20 的用户:

from User u where u.org.name=:orgname and u.yearold>:yearold

query.setParameter(“orgname”,”Blogjava”);

query.setParameter(“yearold”,20);

可以看到这样的查询语句比 sql 更简单多了,同时也更容易理解多了。

2.      实体集合

实体集合过滤形式的查询在实际的项目中也经常会碰到,仍然用上面的例子,但改为通过 Organization 去查询:

from Organization org where org.name=:orgname and org.users.yearold>:yearold

是不是比 sql 简单多了,而且更容易理解呢, ^_^

这个时候对象化查询语句的优势就体现出来了,而不用陷入 sql 的那种关系型的通过外键进行查询的方式。

Slide 190: 区分值( Value )类型和实体( Entity )类型 Hibernate 把持久化类的属性分为两种:? 值( Value )类型和实体( Entity )类 型。 值类型和实体类型的最重要的区别是前? 者没有 OID ,不能被单独持久化,它的 生命周期依赖于所属的持久化类的对象 的生命周期,组件类型就是一种值类型 ;而实体类型有 OID ,可以被单独持久 化。

Slide 191: 区分值( Value )类型和实体( Entity )类型 假定 Customer 类有以下属性:? private String name; private int age; private Date birthday; // Customer 和 Address 类是组成关系 private Address homeAddress; private Address comAddress; //Customer 和 Company 类是多对一关联关系 private Company currentCompany; //Customer 和 Order 类是一对多关联关系 private Set orders; 在以上属性中, name 、 age 、 birthday 、 homeAddress 以及 comAddress 都是? 值类型属性,而 currentCompany 是实体类型属性, orders 集合中的 Order 对象 也是实体类型属性。当删除一个 Customer 持久化对象时, Hibernate 会从数据库 中删除所有值类型属性对应的数据,但是实体类型属性对应的数据有可能依然保 留在数据库中,也有可能被删除,这取决于是否在映射文件中设置了级联删除。 假如对 orders 集合设置了级联删除,那么删除 Customer 对象时,也会删除 orders 集合中的所有 Order 对象。假如没有对 currentCompany 属性设置级联删除 ,那么删除一个 Customer 对象时, currentCompany 属性引用的 Company 对象 依然存在。

抱歉!评论已关闭.