`

小弦教你学hibernate

 
阅读更多

映射关联关系

建立从OrderCustomer的多对一关联关系

public class Order {

              private Integer id ;

              private String orderno ;

              private float price;

 

/* 建立从OrderCustomer的多对一关联关系 */

             private Customer customer ;

             ...//get/set

}

要建立多对一关联 ,我在Order类里边加属性。

关联关系 以属性声明的方式体现,所以在Order里边加一个private Customer customer

性。

--------------------------------------

 

映射文件Order.hbm.xml

<hibernate-mapping package="cn.itcast.hibernate.domain">

              <class name="Order" table="orders" lazy="false">

                     <id name="id" column="id" type="integer">

                            <!-- 主键生成策略 -->

                            <generator class="identity" />

                     </id>

                     <property name="orderno" column="orderno" type="string" length="20" />

                     <property name="price" column="price" type="float"  />

                    

                     <!-- 关联元素 -->

                     <many-to-one name="customer" column="cid" class="Customer" />

                     <!--多对一单向关联,是从Order出发 ,往Customer映射-->

              </class>

       </hibernate-mapping>

<set inverse="true">

       inverse:反转,让缓存忽略的set的集合变化.set失去对关联关系的控制权.只按照对端的状态更新数据库.

 

级联保存:

       保存CustomerOrder对象时,如果只保存Order,不保存Customer,会出现临时对象异常(TransientObjectException),

       可以设置many-to-one元素的cascade属性为save-update,hibernate会自动将和Order关联的Customer保存和更新了.

              Order.hbm.xml

       <many-to-one name="customer" column="cid" class="Customer" cascade="save-update" />

 

常见操作:

 

public void insert(){

       Session s = sf.openSession();

       Transaction tx = s.beginTransaction();

       Customer c = new Customer();

       c.setAge(12);

      

       Order o = new Order();

       o.setOrderno("No009");

       o.setPrice(500f);

 

       o.setCustomer(c);

       s.save(c);

       s.save(o);

    tx.commit();

    s.close();

}

我是先保存c好还是先保存o好呢??答案是先保存c好,因为如果先保存oorders表有外键,会先把外键置为空,然后在保存c,最后知道外键值了还要有一步跟新oders表操作。

------------------------------------------------

建立CustomerOrder之间一对多关联

       1.Customer.java

       {     //建立从CustomerOrder之间的一对多关联关系

              private Set <Order> orders = new HashSet<Set>();

       }

映射文件

       <!-- 映射一对多关联关系(关联元素) -->

       <set name="orders"> name是属性名称

              <key column="cid" />    columnorders表的外键

              <one-to-many class="cn.itcast.hibernate.domain.Order"/>

       </set>

可以在set集合中设置属性cascade="save-update",我保存Customer的同时,也会把客户的订单保存起来。

cascade属性(包括set元素的cascade)都是指操作行为的传播,即对关联的对象是否也能执行相同的操作.

可以包括的级联操作有save-update,delete.

接下来是重点哦??想想,我们为什么还要建立从客户到订单的一对多关系呢??

       建立一对多关系,也就是在Customer类中设一个Set <Order> order,的主要用途在于查询。当我们按照Customerid 查询一个客户(Customer对象)时,就会也同时查询到,这个客户有多少个订单咯。。。

public void loadCustomer(){

       Session s = sf.openSession();

       Transaction tx = s.beginTransaction();

       Customer  c = (Customer)s.load(Customer.class,1);

       Set<Order> orders = c.gerOrders();

       for(Order o:orders){

       System.out.println(o.getId());

       }

       tx.commit();

       s.close();

}             

                // 保存

                public void saveData(){

                     Session s = sf.openSession();

                     Transaction tx = s.beginTransaction();

                     Customer c = new Customer();

                     Order o = new Order();

                     //设置双向关系,保证程序健壮性

                     o.setCustomer(c);

                     c.getOrders().add(o);

                     s.save(c);

                     //s.save(o);

                    

                     tx.commit();

                     s.close();

                }

 

映射一对多双向关联关系时的注意点:

通常情况下:

1.

one方,把<set>元素的inverse属性设为true,<set inverse="true">

       inverse:反转,让缓存忽略set的集合变化。set失去对关联关系的控制权.只按照另一端的状态更新数据库.提高应用性能。

 

2.one方,如果设把<set>元素的cascade="save-update"

<set name="orders" cascade="save-update" inverse="true">

 

这样做是为了,因为CustomerOrder是一对多的关系,如果想保存Customer的同时,保存Order,就

 

要设置级联保存。总的来说通常情况下把<set>元素中,cascade="save-update" inverse="true"

 

理解<set>元素的inverse属性:举例

<set name="orders" cascade="save-update" inverse="true">

 

       public void insert(){

              Session s = sf.openSession();

              Transaction tx = s.beginTransaction();

              Customer c = new Customer();

              c.setName("tomas");

             

              Order order = new Order();

             

              order.setCustomer(customer);//建立从OrderCustomer的关联关系

              //customer.getOrders.add(order);不建立从CustomerOrder的关联关系

 

              tx.commit();

              s.close();

       }

       设置了Ordercustomer属性,Hibernate就会按照Order对象的变化来同步更新数据库。

而如果

 

       public void insert(){

              Session s = sf.openSession();

              Transaction tx = s.beginTransaction();

              Customer c = new Customer();

              c.setName("tomas");

             

              Order order = new Order();

             

              //order.setCustomer(customer);不建立从OrderCustomer的关联关系

              customer.getOrders.add(order);建立从CustomerOrder的关联关系

 

              tx.commit();

              s.close();

       }

而如果仅设置了Customerorders属性,由于<set>元素的inverse属性为true,因此Hibernate不会按照Customer对象的属性变化同步更新数据库。

补充:说白了吧。Customer 有orders 集合属性,而在Customer这边的映射文件中把<set>元素的inverse属性设为true,所以在保存Customer对象的时候,hibernate不会同步更新数据库.

引发数据错误。 hibernate不会按照Customer对象的属性变化而更新数据库.

所以我们在保存对象的时候,要尽量从Order一方下手,因为Order这边的映射文件

inverse是默认的false,保存order会同步更新数据库.

3.通常情况下,让one方的<set inverse="true">,而在many方,设置级联保存和更新,

<many-to-one name="customer" column="cid" class="Customer" cascade="save-update"/>

------------------------------------------------------------------------------------------

常见问题

PropertyValueException异常

<many-to-one>not-null,2个值,一个是true,一个是false.默认值是false,就是外键可以为空,

 

而在表中如果设了外键不可以为空的话,我又在<many-to-one not-null="true">就是可以不为空

 

我用session只保存了Order,而没有先保存Customer的话,Hibernate会向orders表中的插入一条记录,而且把外键设为null,这样就矛盾了,所以会报PropertyValueException异常。

 

映射组成关系

public class Customer{

       id,

       name

}

public class Address{

       private String province;

       private String city;

       private String street;

       private String zipcode;

}

-----------------------------------------------------------------------------------------------------------------------------

一对一映射

外键关联 和多对一映射方式类似,通过多对一来模拟的

       外键具有唯一性

public class User{

       private Integer id;

       private String name;

       private Adder adder;

}

public class Addr{

       private Integer id;

       private String province;

       private User user;

}

 

Addr.hbm.xml

       <class name="Addr" table="addr_fk" lazy="false">

              <id name="id" column="id" type="integer">

                     <generator class="identity"/>

              </id>

              <property name="province" column="province" type="String" length="20">

 

<!--关联元素,唯一性约束-->

              <many-to-one name="user" column="userid" class="User" unique="true"/>

       </class>

 

User.hbm.xml

       <class name="User" table="addr_fk" lazy="false">

              <id name="id" column="id" type="integer">

                     <generator class="identity"/>

              </id>

              <property name="name" column="name" type="String" length="20">

 

<!--关联元素,映射UserAddr的一对一关联,property-ref属性参考,指定对端的关联属性-->

              <one-to-one name="addr" property-ref="user"/>

       </class>

 

-----------------------------------------------------------------------------------------

 

主键关联

 

User.hbm.xml

<class name="User" table="user_pk" lazy="false">

      <id name="id" column="id" type="integer">

             <generator class="identity"/>

      </id>

      <property name="name" column="name" type="string" length="20"/>

            

      <one-to-one name="addr" class="Address"/>

</class>

 

Address.hbm.xml

<id name="id" colunm="id" type="integer">

       <generator class="foreign"/>  从外部提取 ,让地址表的主键跟随用户表的主键保持一致

              <param property="user"> </param>

</id>

<one-to-one name="user" class="User" constrained="false"/>

 

我的id值是从外部的一个属性提取的 user属性

constrained:受到约束的,user!=null user.id!=null

 

----------------------------------------------------------------------------------------

多对多关联

public class Teacher{

 

       private Integer id;

       private String teaNo;

       private Set<Student> students = new HashSet<Student>();

}à一个教师有多个学生

 

//集合中的每个元素类型都是学生

public class Student{

 

       private Integer id;

       private String stuName;

       private Set<Teacher> teachers = new HashSet<Teacher>();

}  à一个学生有多个教师,两边都是一对多

 

-----------------------------------------------------------------------------------------

Teacher.hbm.xml

<!--映射多对多关系,要指定中间表links-->

<!--多对多关系要维护中间表,如果两边都维护的话,导致记录的冲突,所以一定要把一端的维护权消除-->

<set name="students" table="links" inverse="true">

       <key column="tid"/>

       <many-to-many class="Student" column="sid"/我要想查一个教师有几个学生,所以一定要查sid>

</set>

Student.hbm.xml

 

<set name="teachers" table="links" >

       <key column="sid"/>

       <many-to-many class="Teacher" column="tid"/>

</set>

-----------------------------------------------------------------------------------------

public class Teacher {

       private Integer id;

       private String teaNo;

       private Set<Student> students = new HashSet<Student>();

       public Integer getId() {

              return id;

       }

       public void setId(Integer id) {

              this.id = id;

       }

       public String getTeaNo() {

              return teaNo;

       }

       public void setTeaNo(String teaNo) {

              this.teaNo = teaNo;

       }

       public Set<Student> getStudents() {

              return students;

       }

       public void setStudents(Set<Student> students) {

              this.students = students;

       }

       //用一个可变参数往集合中添加元素

       public void addStudent(Student... students){

              for(Student s : students){

                     getStudents().add(s);

              }

       }

}

-----------------------------------------------------------------------------------------

public void save(){

       t1.addStudent(s1,s2,s3);

       s2.addTeacher(t1,t2);

}

-----------------------------------------------------------------------------------------

 

映射自关联 和多对一类似

 

parentid 引入上边的主键值

 

public calss Area{

       private Integer id;

       private String name;

       //建立到上级的多对一关系

       private Area parentArea;

       //建立到下级的一对多关系

       Private Set<Area> children =new HashSet<Area>();

}

Area.hbm.xml

//建立自关联的多对一关系

<many-to-one name="parentArea" column="parentid" class="Area"/>

//建立自关联的一对多关系

<set name="children" inserse="true">

       <key colunm="parentid">

       <one-to-many class="Area">

</set>

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics