关联关系映射
1、一对多多对一
对于一对多的关系,我们一般是建立两张表就行了,比如客户跟订单,建立一个客户表、一个订单表就行了,然后在多的一方维护这个外键。
为了演示一对多和多对一的操作,这里我举两个例子,第一个例子是客户跟订单的关系,一个客户对应多个订单,每个订单都只属于一个客户,所以构成了一对多的关系;第二个例子是自我映射一对多多对一,这个做法一般用于菜单表的设计;
2.1一对多演示:客户-->订单操作
说明:为了演示这个客户订单的一对多操作,我们首先的新建两个实体类、然后编写这两个实体类的映射文件,然后再写个测试类,验证我们的想法
客户类 |
public class Customer implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id; private String userName; private Set<Orders> orders = new HashSet<Orders>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Set<Orders> getOrders() { return orders; } public void setOrders(Set<Orders> orders) { this.orders = orders; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((userName == null) ? 0 : userName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Customer other = (Customer) obj; if (userName == null) { if (other.userName != null) return false; } else if (!userName.equals(other.userName)) return false; return true; }
} |
客户类的映射文件 |
<class name="Customer" table="Customer"> <id name="id"> <generator class="native"/> </id> <property name="userName" column="USERNAME" /> <set name="orders"> <key column="CUSTOMER_ID" /> <one-to-many class="Orders"/> </set> </class> |
订单类 |
public class Orders implements Serializable{
private static final long serialVersionUID = 123284204L;
private Integer id; private String orderNum; private Double price; private Customer customer; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getOrderNum() { return orderNum; } public void setOrderNum(String orderNum) { this.orderNum = orderNum; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((orderNum == null) ? 0 : orderNum.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Orders other = (Orders) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (orderNum == null) { if (other.orderNum != null) return false; } else if (!orderNum.equals(other.orderNum)) return false; return true; } @Override public String toString() { return "Orders [id=" + id + ", orderNum=" + orderNum + ", price=" + price + "]"; } } |
订单类的映射文件 |
<class name="Orders" table="Orders"> <id name="id"> <generator class="native"/> </id> <property name="orderNum" column="ORDERNUM" /> <property name="price" column="PRICE" /> <many-to-one name="customer" column="CUSTOMER_ID" class="Customer"> </many-to-one> </class> |
演示新增客户和订单信息 |
/** * 新增订单和客户信息,映射文件中全部都用默认配置 * 步骤: * 1、创建客户对象 * 2、创建订单对象 * 3、在订单一方设置订单和客户的关联关系 * 4、保存订单 * 5、保存客户 * 注意: * 1>、如果先保存订单,再保存客户,会产生三条语句,两条新增语句,一条更新语句,第一条语句是新增 * 客户信息,第二条语句是新增订单信息(此时订单信息的外键"客户id"是为null的),更新语句是 * 将订单表的外键(客户id)进行更新; * 2>、如果先保存客户,再保存订单,只会产生两条语句,两条新增语句,而不会产生更新语句 * 因为在新增订单的时候,已经拿到了客户的主键作为外键插入到订单表中去了 * Customer.hbm.xml文件配置如下: <hibernate-mapping package="com.itheima.domain"> <class name="Customer" table="Customer"> <id name="id"> <generator class="native"/> </id> <property name="userName" column="USERNAME" /> <set name="orders"> <key column="CUSTOMER_ID" /> <one-to-many class="Orders"/> </set> </class> </hibernate-mapping>
* 6、Orders.hbm.xml文件配置如下: <hibernate-mapping package="com.itheima.domain"> <class name="Orders" table="Orders"> <id name="id"> <generator class="native"/> </id> <property name="orderNum" column="ORDERNUM" /> <property name="price" column="PRICE" /> <many-to-one name="customer" column="CUSTOMER_ID" class="Customer"> </many-to-one> </class> </hibernate-mapping> */ @Test public void insert1(){ //创建客户对象 Customer c = new Customer(); c.setUserName("张三");
//创建订单对象 Orders or = new Orders(); or.setOrderNum("o_001"); or.setPrice(35.2);
//设置客户和订单的关联关系 or.setCustomer(c);
//先保存订单 session.save(or); //再保存客户 session.save(c); } |
演示级联新增客户和订单信息:注意要先修改映射文件的级联属性的值 |
/** * 级联新增,在订单对象的映射文件中设置级联属性cascade="save-update" <many-to-one name="customer" column="CUSTOMER_ID" class="Customer" cascade="save-update"> </many-to-one> 这样的话,当设置好订单对象和客户对象的关联关系,再保存订单的时候,客户信息就不需要再save了, 因为客户对象已经被自动插入到客户表中去了; 反过来也是一样,如果客户对象的映射文件设置了级联属性cascade="save-update", <set name="orders" cascade="save-update"> <key column="CUSTOMER_ID" /> <one-to-many class="Orders"/> </set> 那么,在新增客户信息的时候,就不需要再单独去新增订单信息了,因为订单信息已经被级联保存进了订单表, 不过,一般如果由多的一方来维护关系的话,性能相对来说要好很多 */ @Test//级联新增 public void insert4(){ //创建客户对象 Customer c = new Customer(); c.setUserName("赵六111");
//创建订单对象1 Orders or1 = new Orders(); or1.setOrderNum("o_001"); or1.setPrice(39.2); //创建订单对象2 Orders or2 = new Orders(); or2.setOrderNum("o_002"); or2.setPrice(39.2); //创建订单对象3 Orders or3 = new Orders(); or3.setOrderNum("o_003"); or3.setPrice(39.2);
//设置客户和订单的关联关系 or1.setCustomer(c); or2.setCustomer(c); or3.setCustomer(c);
//在订单对象的映射文件设置好级联后,当订单保存时候会将对应的客户信息先保存到数据库,所以这里不用再单独save(客户信息)了 session.save(or1); session.save(or2); session.save(or3); } |
2.2 一对多演示:自我映射,演示商品分类
说明:为了演示自我映射,我们先定义一个Category类,然后编写这个类的映射文件,再写个测试类来测试以下自我映射是如何操作的:
类别类 |
public class Category implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id; private String name; //父类别 private Category parentCategory; //子类别 private Set<Category> childCategories = new HashSet<Category>();
public Category(){}
public Category(String name){ this.name = name; }
public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Category getParentCategory() { return parentCategory; } public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; } public Set<Category> getChildCategories() { return childCategories; } public void setChildCategories(Set<Category> childCategories) { this.childCategories = childCategories; } @Override public String toString() { return "Category [id=" + id + ", name=" + name + "]"; } } |
映射文件 |
<class name="Category" table="CATEGORY"> <id name="id"> <generator class="native"/> </id> <property name="name" column="NAME" /> <!-- 把商品类别看作多的一方来操作,配置多对一,这时候多的一方就是子级菜单, 一的一方就是父级菜单 --> <many-to-one name="parentCategory" class="Category" column="category_id" />
<!-- 把商品类别看作一的一方来操作,配置一对多,这时候,一的一方代表的就是父级菜单, 多的一方代表的就是子级菜单 --> <set name="childCategories" cascade="save-update" inverse="true"> <key column="category_id" /> <one-to-many class="Category"/> </set> </class> |
级联新增父类别和子类别 |
/** * 新增类别: * 由于在一的一方配置了级联新增,所以新增一个父级类别的同时会自动新增该父级类别下的所有子类别 */ @Test public void insert(){ //一级分类 Category computer = new Category("电脑"); Category part = new Category("配件");
//二级分类 Category thinkPad = new Category("thinkPad"); Category apple = new Category("apple");
Category cpu = new Category("CPU"); Category mouse = new Category("mouse");
//建立关系 computer.getChildCategories().add(thinkPad); computer.getChildCategories().add(apple);
thinkPad.setParentCategory(computer); apple.setParentCategory(computer);
part.getChildCategories().add(cpu); part.getChildCategories().add(mouse);
cpu.setParentCategory(part); mouse.setParentCategory(part);
session.save(computer); session.save(part); } |
更改商品类别所属:也就是将一个类别从原来的大类别下面移动到另外一个大类别下面去 |
/** * 修改子类别所属的父类别:鼠标原来是配件类别下的子类,现在要将鼠标移动到电脑下面去,具体的步骤应该是: * 1、移除老关系 * 2、建立新关系 * 但是呢,由于建立新关系的同时可以去覆盖掉老关系,所以,不用单独刻意的去移除老关系 */ @Test public void update(){ //拿到电脑 Category computer = (Category)session.get(Category.class, 1); //拿到鼠标 Category mouse = (Category)session.get(Category.class, 5);
//建立新关系 computer.getChildCategories().add(mouse); mouse.setParentCategory(computer);
} |
2.3、一对多映射List
实体类的修改: |
在Customer.java中修改原来的Set集合为List private List<Orders> orders = new ArrayList<Orders>(); public List<Orders> getOrders() { return orders; } public void setOrders(List<Orders> orders) { this.orders = orders; } |
映射文件的修改(Customer.hbm.xml): |
<class name="Customer" table="Customer"> <id name="id"> <generator class="native"/> </id> <property name="userName" column="USERNAME" /> <list name="orders" table="Orders"> <key column="CUSTOMER_ID" />
<!-- base=”1”代表每次这个从员工表中查询员工的时候,这个集合的索引从1开始,因为我数据库里Employee表的ID字段的主键最小是从1开始的,所以base要配置为1,说实话如果要配置list集合的映射的话,数据库的主键生成策略最好用increment,确保主键的增长是连续的,没有间断的,不然每次在迭代员工表的数据的时候你都得判断查出来的对象是否为空,比如说当你list.get(3)的时候,你Employee表没有id=3的这条数据了,这时候很可能引发空指针异常 --> <list-index column="ID" base=”1” /> <one-to-many class="Orders" /> </list> </class> |
测试: |
@Test public void getOrdersByCustomer(){ Customer c = (Customer)session.get(Customer.class, 2); List<Orders> list = c.getOrders(); for(int i=0; i<list.size(); i++){ //这个地方就是为了防止数据库中主键不连续,导致根据索引获取到的数据为 空而引发的空指针异常 if(list.get(i)==null)continue; System.out.println(list.get(i).getOrderNum()); } } |
2、映射多对多的关联关系
对于多对多关联关系,一般是要建立三张表的,比如说老师跟学生的关系是多对多的关系,那么我们会建立一张教师表、一张学生表、一张教师和学生的关联关系表,按照这个思路,下面我们来进行操作:
实体类:
Teacher.java |
public class Teacher implements Serializable{ private static final long serialVersionUID = 1L; private Integer id; private String name; private Set<Student> students = new HashSet<Student>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; }
} |
Student.java |
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id; private String name; private Set<Teacher> teachers = new HashSet<Teacher>();
public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; }
} |
映射文件:
Teacher.hbm.xml
<class name="Teacher" table="TEACHER"> <id name="id"> <generator class="native"/> </id> <property name="name" column="NAME" /> <set name="students" table="TEACHER_STUDENT" cascade="save-update"> <key column="TEACHER_ID" /> <many-to-many column="STUDENT_ID" class="Student" /> </set> </class> |
Student.hbm.xml
<class name="Student" table="STUDENT"> <id name="id"> <generator class="native"/> </id> <property name="name" column="NAME" /> <set name="teachers" table="TEACHER_STUDENT"> <key column="STUDENT_ID" /> <many-to-many column="TEACHER_ID" class="Teacher" /> </set> </class> |
生成的表结构
TEACHER
STUDENT
TEACHER_STUDENT
B、多对多操作
注:没有父子概念(也就木有孤儿删除),级联慎用,一旦级联删除,可能导致两个表的数据都Game Over了
添加:(不要重复维护关系,有一方维护关系就行了,原因是不行,因为维护一次关系就相当于在teach_student表中新增了一条数据,你再维护一次就相当于再次添加了一条相同的数据,这时候肯定就会报错了)
测试多对多的新增 |
@Test public void insert(){ Teacher t1 = new Teacher(); t1.setName("t1");
Teacher t2 = new Teacher(); t2.setName("t2");
Student s1 = new Student(); s1.setName("s1");
Student s2 = new Student(); s2.setName("s2");
//建立老师和学生的关系,其实就是在teacher_student表插入四条数据 t1.getStudents().add(s1); t1.getStudents().add(s2); t2.getStudents().add(s1); t2.getStudents().add(s2);
session.save(t1); session.save(t2); //如果在Teacher.hbm.xml文件中对集合属性设置cascade=”save-update”, //那么下面这两句代码是不需要写的,因为会级联保存嘛 session.save(s1); session.save(s2); } |
解除t1和s1的关系(不用双向解除关联关系,原因是不必要,因为解除关系就相当于从teacher_student表中删除一条数据,你第二次解除的时候已经没有这条数据量,不需要再次删除了)
/** * 解除t1和s1的关系 */ @Test public void delete1(){ Teacher t1 = (Teacher)session.get(Teacher.class, 1); Student s1 = (Student)session.get(Student.class, 1); t1.getStudents().remove(s1); } |
解除t1和s2的关系,改为t1和s1关联(不是更新是删除后添加)
/** * 解除t1和s2的关系,同时建立t1和s1的关系 */ @Test public void delete2(){ Teacher t1 = (Teacher)session.get(Teacher.class, 1); Student s1 = (Student)session.get(Student.class, 1); Student s2 = (Student)session.get(Student.class, 2); t1.getStudents().remove(s2); t1.getStudents().add(s1); } |
删除s2学生(先删第三方表关系后删学生)
/** * 删除学生s2 * Hibernate会先删除s2关联关系,然后再删除s2,所以下面会打印三条语句, * 一条查询,两条删除 */ @Test public void delete3(){ Student s2 = (Student)session.get(Student.class, 2); session.delete(s2); } |
能否删除t1能否同时删除s1和s2(可以,但是很危险,因为一旦级联删除,很可能将这三个表的其他数据都删除掉,所以,对于级联删除要慎用)
Teacher.hbm.xml:<setname="students" table="TEACHER_STUDENT" cascade="delete">
结论:傻眼!咋全都干掉了呢?所以说,慎用级联删除啊
3、外键关联(演示一对一的关联关系)
映射文件
IdCard.hbm.xml
Person.hbm.xml
property-ref属性指定使用被关联实体主键以外的字段作为关联字段
相关操作
4、主键关联(演示一对一关联映射)
A、映射文件
IdCard.hbm.xml
Person.hbm.xml
B、相关操作
八、映射组成关系
有这样一个需求,设计一个客户类,
有客户id、name、
homeProvince、homeCity、homeStreet、homeZipCode、
comProvince、comCity、comStreet、comZipCode这么一些属性,
从这些属性中我们发现一个问题,如果将这些字段放在Customer类中,难免显得有些粗糙,因为(homeProvince、homeCity、homeStreet、homeZipCode)和
(comProvince、comCity、comStreet、comZipCode)的意义都是一样的,只是名称不一样,这时候,我们可以考虑用更细粒度的编程,将省份、城市、街道、门牌号这些属性单独定义到一个类中(Address.java),然后在Customer类中使用这个类的对象即可。
A、对象设计要细(类越多越好),数据库设计要粗(表越少越好)
域模型
表模型
B、编写组合关系映射实例类:
客户信息实体类 |
public class Customer implements Serializable{ private static final long serialVersionUID = 1L; private Integer id; private String name; private Address homeAddress; private Address comAddress; |
地址信息类 |
//不是实体,不需要单独写一个映射文件 public class Address implements Serializable{ private static final long serialVersionUID = 1L; private String province; private String city; private String street; private String zipCode; |
C、映射文件
<class name="Customer" table="CUSTOMER"> <id name="id" column="ID"> <generator class="native"/> </id> <property name="name" column="NAME"></property> <!-- 映射组成关系 --> <component name="homeAddress" class="Address"> <property name="province" column="HOME_PROVINCE"/> <property name="city" column="HOME_CITY"/> <property name="street" column="HOME_STREET"/> <property name="zipCode" column="HOME_ZIP_CODE"/> </component> <component name="comAddress" class="Address"> <property name="province" column="COM_PROVINCE"/> <property name="city" column="COM_CITY"/> <property name="street" column="COM_STREET"/> <property name="zipCode" column="COM_ZIP_CODE"/> </component> </class> |
D、操作
添加
//添加操作:实际上是对单表的操作 @org.junit.Test public void insert() { Session s = null; Transaction tx = null; try { s = HibernateUtil.getSession(); tx = s.beginTransaction();
Customer c = new Customer(); c.setName("乐哥");
Address homeAddress = new Address(); homeAddress.setProvince("江苏"); homeAddress.setCity("盐城"); homeAddress.setStreet("XX街道"); homeAddress.setZipCode("380000");
Address comAddress = new Address(); comAddress.setProvince("北京"); comAddress.setCity("海淀"); comAddress.setStreet("东北旺"); comAddress.setZipCode("100000");
c.setHomeAddress(homeAddress); c.setComAddress(comAddress);
s.save(c);
tx.commit(); } catch (Exception e) { if (tx != null) tx.rollback(); e.printStackTrace(); } finally { if (s != null) s.close(); } } |
查询
// 查询 @org.junit.Test public void query() { Session s = null; Transaction tx = null; try { s = HibernateUtil.getSession(); tx = s.beginTransaction();
Customer c = (Customer) s.get(Customer.class, 1); System.out.println(c);
tx.commit(); } catch (Exception e) { if (tx != null) tx.rollback(); e.printStackTrace(); } finally { if (s != null) s.close(); } } |
修改:注意空指针问题
// 修改地址:修改公司邮编 @org.junit.Test public void update() { Session s = null; Transaction tx = null; try { s = HibernateUtil.getSession(); tx = s.beginTransaction();
Customer c = (Customer) s.get(Customer.class, 1); Address comAddress = c.getComAddress(); if (comAddress == null) { comAddress = new Address(); comAddress.setProvince("北京"); comAddress.setCity("海淀"); comAddress.setStreet("东北旺"); comAddress.setZipCode("100000"); c.setComAddress(comAddress); } else { comAddress.setZipCode("100001"); }
tx.commit(); } catch (Exception e) { if (tx != null) tx.rollback(); e.printStackTrace(); } finally { if (s != null) s.close(); } } |
九、继承关系映射
9.1继承关系及三种映射策略概述
需求:系统中有员工这么一个类,但是员工又分为小时工、正式工,这时候我们可以考虑新建一个员工类、一个小时工类、一个正式工类,然后让小时工类和正式工类继承这个员工类。下面我们就演示一下,如何配置这种有继承关系的映射。
建立实体类(为节省空间这里面的构造方法和get、set方法都省略了...) |
员工实体类:Employ.java |
public class Employee implements Serializable{ private static final long serialVersionUID = 1L; private Integer id; private String name; |
小时工实体类:HourEmployee.java |
public class HourEmployee extends Employee { private static final long serialVersionUID = 1L; private Float rate; |
正式工实体类:SalariedEmployee.java |
public class SalariedEmployee extends Employee { private static final long serialVersionUID = 1L; private Float salary; |
有继承关系的子父类的三种映射策略介绍 对于这三种策略,实体类都是一样的,三个实体类,唯一不同的就是配置文件,配置文件不同,数据库表肯定也是不同的 |
策略一: |
父类和子类的数据放在同一张表中,引入鉴别(discriminator)字段来区分子类的数据(subclass)
|
策略二: |
父类和子类的数据放在不同的表中,子类的数据通过表的外键建立与父类的关联,公共数据放在父表,子类数据放在子表。(joined subclass) EMPLOYEE表 HOURLY_EMPLOYEE表 SALARIED_EMPLOYEE表
|
策略三: |
父类和子类的数据放在不同的表中,子类表和父类表没有关系,子类表中存放父类信息,且 信息都是完整的。(union subclass 了解) EMPLOYEE表 HOURLY_EMPLOYEE表 SALARIED_EMPLOYEE表
|
9.2父类子类所有数据在同一张表中
A、映射文件
只需要Employee.hbm.xml即可,HourEmployee.hbm.xml和SalariedEmploy.hbm.xml都不需要写
<class name="Employee" table="EMPLOYEE" discriminator-value="EE"> <id name="id"> <generator class="native"/> </id> <!-- 定义鉴定字段,给Hibernate用的,会映射一个名称为EMPLOYEE_TYPE的字段到数据库里去 --> <discriminator column="EMPLOYEE_TYPE" type="string"></discriminator> <!-- 按照该文档引入的dtd约束,Employee类的属性必须放在鉴定字段的后面 --> <property name="name" type="string" column="name" /> <!-- 配置子类型 --> <subclass name="HourEmployee" discriminator-value="HE"> <property name="rate" column="rate"></property> </subclass> <subclass name="SalariedEmployee" discriminator-value="SE"> <property name="salary" column="salary"></property> </subclass> </class> |
B、相关操作
分别添加正式工、小时工、普通员工
/** * 增加正式工数据 */ @Test public void insertSalariedEmployee(){ SalariedEmployee se = new SalariedEmployee(); se.setName("张三"); se.setSalary(9000.0f); session.save(se); } |
/** * 增加小时工数据 */ @Test public void insertHourEmployee(){ HourEmployee he = new HourEmployee(); he.setName("李四"); he.setRate(10000.0f); session.save(he); } |
/** * 增加普通员工数据 */ @Test public void insertNormalEmployee(){ Employee he = new Employee(); he.setName("王五"); session.save(he); } |
查询所有员工
/** * 查询所有员工 */ @Test public void getAllEmployee(){ List<Employee> empList = session.createQuery("from Employee").list(); for(Employee emp : empList){ System.out.println(emp.getName()); } } |
查询所有小时工
/** * 查询所有小时工 */ @Test public void getAllHourEmployee(){ List<Employee> empList = session.createQuery("from HourEmployee").list(); for(Employee emp : empList){ System.out.println(emp.getName()); } } |
9.3父类子类数据在独自的表中
域模型不需要变动,只需要更改映射文件即可;操作也不用变
A、映射文件
Employee.hbm.xml
<class name="Employee" table="EMPLOYEE"> <id name="id"> <generator class="native"/> </id> <property name="name" type="string" column="name" /> <joined-subclass name="HourEmployee" table="HourEmployee"> <!-- 当前子类在其他地方对应的外键 --> <key column="EMPLOYEE_ID" /> <property name="rate" column="rate" /> </joined-subclass> <joined-subclass name="SalariedEmployee" table="SalariedEmployee"> <!-- 当前子类在其他地方对应的外键 --> <key column="EMPLOYEE_ID" /> <property name="salary" column="salary" /> </joined-subclass> </class> |
B、相关操作
与策略一的操作是一样一样滴
对于删除操作,当做单表即可,比如当你删除一个正式工的时候,Hibernate会帮你同时删除掉SalariedEmployee表中的正式工的那条数据以及和该正式工相关的Employee表中的那条数据,反过来也是一样的,当你删除掉Employee表中的一条数据的时候,SalariedEmployee表中引用了Employee表中的那条数据也会被同时干掉:
@Test public void delete(){ SalariedEmployee se = (SalariedEmployee)session.get(SalariedEmployee.class, 1); session.delete(se); }
@Test public void deleteEmployee(){ Employee se = (Employee)session.get(Employee.class, 2); session.delete(se); } |
9.4每个子类一张表,都包含所有信息
了解即可
域模型及操作一概不变,只更改映射文件。不能使用native主键生成策略。可以使用与数据库无关的increment策略
A、映射文件
9.5对比三种映射方式
推荐使用后2种