由于 之前的书上讲的方法 有的很不安全 Bug不断 结构也不够清晰 在做例子程序是反复调试还是出错
在加上书上所用的 ant 和 hibernate 还有 hibernate tools 版本太旧
固自己研究reference 做总结
一 Table per class hierarchy (每个类分层结构一张表)
例子
Company 和 Employee 一对多 Employee 有两个子类 HourlyEmployee 和 SalaruedEmployee
Company.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Company" table ="COMPANIES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< set name ="employees"
inverse ="true"
lazy ="true" >
< key column ="COMPANY_ID" />
< one-to-many class ="ergal.Employee" />
</ set >
</ class >
</ hibernate-mapping >
Employee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="native" />
</ id >
< discriminator column ="EMPLOYEE_TYPE" type ="string" />
< property name ="name" column ="NAME" type ="string" />
< many-to-one name ="company"
column ="COMPANY_ID"
class ="ergal.Company" />
< subclass name ="ergal.HourlyEmployee" discriminator-value ="HE" >
< property name ="rate" column ="RATE" type ="double" />
</ subclass >
< subclass name ="ergal.SalariedEmployee" discriminator-value ="SE" >
< property name ="salary" column ="SALARY" type ="double" />
</ subclass >
</ class >
</ hibernate-mapping >
hbm2java
工具会自动产生
Employee.java
HourlyEmplyee.java
SalariedEmployee.java
并自动完整他们得继承关系
hbm2ddl
工具会自动产生
2个表
COMPANYS和EMPLOYEES
EMPLOYEES中多了个EMPLOYEE_TYPE字段
EMPLOYEES
6 个字段
1 - ID
2 - EMPLOYEE_TYPE
3- NAME
4 - COMPANY_ID
5 - RATE
6 - SALARY
优点:方便查询 只需建立一张表 支持多态查询和多态关联 不需要查询时连接 可维护性较强
缺点:有额外的字段
Inheritance strategy | Polymorphic many-to-one | Polymorphic one-to-one | Polymorphic one-to-many | Polymorphic many-to-many | Polymorphic load()/get() | Polymorphic queries | Polymorphic joins | Outer join fetching |
---|---|---|---|---|---|---|---|---|
table per class-hierarchy | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
二 Table per subclass (每个子类一张表)
例子同上
Company 和 Employee 一对多 Employee 有两个子类 HourlyEmployee 和 SalaruedEmployee
Company.hbm.xml
没有变化
Employee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< many-to-one name ="company"
column ="COMPANY_ID"
class ="ergal.Company" />
< joined-subclass name ="ergal.HourlyEmployee" table ="HOURLY_EMPLOYEE" >
< key column ="EMPLOYEE_ID" />
< property name ="rate" column ="RATE" type ="double" />
</ joined-subclass >
< joined-subclass name ="ergal.SalariedEmployee" table ="SALARUED_EMPLOYEE" >
< key column ="EMPLOYEE_ID" />
< property name ="salary" column ="SALARY" type ="double" />
</ joined-subclass >
</ class >
</ hibernate-mapping >
运行hbm2ddl工具会在数据库中产生4个表
COMPSNYS EMPLOYEES HOURLYE_MPLOYEE 和SALARIED_EMPLOYEE
EMPLOYEES 3个字段
1 - ID
2 - NAME
3 - COMPANY_ID
HOURLYE_MPLOYEE 2个字段
1 - EMPLOYEE_ID
2 - RATE
SALARIED_EMPLOYEE 2个字段
1 - EMPLOYEE_ID
2 - SALARY
运行hbn2java工具
会自动产生
Employee.java
HourlyEmplyee.java
SalariedEmployee.java
并使他们具备完整的继承关系
优点:支持多态查询和多态关联 某个类要修改可以修改相应的这个类对应的表
缺点:表的数目多 表之间有外键参照关系 查询时需要连接
Inheritance strategy | Polymorphic many-to-one | Polymorphic one-to-one | Polymorphic one-to-many | Polymorphic many-to-many | Polymorphic load()/get() | Polymorphic queries | Polymorphic joins | Outer join fetching |
---|---|---|---|---|---|---|---|---|
table per class-hierarchy | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
table per subclass | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
三 Table per subclass, using a discriminator (使用标识符的 每个子类一张表)
例子同上
Company 和 Employee 一对多 Employee 有两个子类 HourlyEmployee 和 SalaruedEmployee
Company.hbm.xml
没有变化
Employee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="native" />
</ id >
< discriminator column ="EMPLOYEE_TYPE" type ="string" />
< property name ="name" column ="NAME" type ="string" />
< many-to-one name ="company"
column ="COMPANY_ID"
class ="ergal.Company" />
< subclass name ="ergal.HourlyEmployee" discriminator-value ="HE" >
< join table ="HOURLY_EMPLOYEE" >
< key column ="EMPLOYEE_ID" />
< property name ="rate" column ="RATE" type ="double" />
</ join >
</ subclass >
< subclass name ="ergal.SalariedEmployee" discriminator-value ="SE" >
< join table ="SALARUED_EMPLOYEE" >
< key column ="EMPLOYEE_ID" />
< property name ="rate" column ="RATE" type ="double" />
</ join >
</ subclass >
</ class >
</ hibernate-mapping >
运行hbm2ddl工具会在数据库中产生4个表
COMPANIES EMPLOYEES HOURLYEMPLOYEE 和SALARIEDEMPLOYEE
其中在EMPLOYEE 中多了用来标识的EMPLOYEE_TYPE 取值为 HE和SE
EMPLOYEES 4个字段
1 - ID
2 - NAME
3 - EMPLOYEE_TYPE
4 - COMPANY_ID
HOURLY_EMPLOYEE 2个字段
1 - EMPLOYEE_TPYE
2 - RATE
SALARIED_EMPLOYEE 2个字段
1 - EMPLOYEE_TPYE
2 - SALARY
运行hbn2java工具
会自动产生
Employee.java
HourlyEmplyee.java
SalariedEmployee.java
并使他们具备完整的继承关系
只是介绍这种映射方式---结合标识器 并没有什么突出的特征和用途
四 Mixing table per class hierarchy with table per subclass (混合模式)
不做更多解释 本身这种映射的意义就不大
reference上的例子
< id name ="id" type ="long" column ="PAYMENT_ID" >
< generator class ="native" />
</ id >
< discriminator column ="PAYMENT_TYPE" type ="string" />
< property name ="amount" column ="AMOUNT" />
...
< subclass name ="CreditCardPayment" discriminator-value ="CREDIT" >
< join table ="CREDIT_PAYMENT" >
< property name ="creditCardType" column ="CCTYPE" />
...
</ join >
</ subclass >
< subclass name ="CashPayment" discriminator-value ="CASH" >
...
</ subclass >
< subclass name ="ChequePayment" discriminator-value ="CHEQUE" >
...
</ subclass >
</ class >
疑问
reference上的这句
对上述任何一种映射策略而言,指向根类Payment的 关联是使用<many-to-one>进行映射的。
<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>
我之前没有做这项工作
并没有报错 而且这么做的话 我原来的多对一 Employee对Company该怎么映射
五 Table per concrete class (每个具体的类一张表) 这里把它叫做 每个具体类一张表(union-subclass) 好一点
它有两种方式来实现
一种是显式多态
一种是隐式多态
显式多态采用的为 @hibernate.union-subclass 的方式,reference上也把这种映射方式叫做每个具体的类(union-subclass)
隐式多态则采用每个具体类的 PO 独立建表的策略,在它的映射文件中将看不出任何的和接口、抽象类的关系,同时对于抽象类,需要指明其 abstract=”true” 。
这里采用的是显式多态
例子同上
Company 和 Employee 一对多 Employee 有两个子类 HourlyEmployee 和 SalaruedEmployee
Company.hbm.xml
没有变化
Employee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< many-to-one name ="company"
column ="COMPANY_ID"
class ="ergal.Company" />
< union-subclass name ="ergal.HourlyEmployee" table ="HOURLY_EMPLOYEES" >
< property name ="rate" column ="RATE" type ="double" />
</ union-subclass >
< union-subclass name ="ergal.SalariedEmployee" table ="SALARIED_EMPLOYEES" >
< property name ="salary" column ="SALARY" type ="double" />
</ union-subclass >
</ class >
</ hibernate-mapping >
同样会产生4个表 但是这个映射是有限制的
官方的reference这么写到
The limitation of this approach is that if a property is mapped on the superclass, the column name must be the same on all subclass tables. (We might relax this in a future release of Hibernate.) The identity generator strategy is not allowed in union subclass inheritance, indeed the primary key seed has to be shared accross all unioned subclasses of a hierarchy.
主要限制在不允许在联合子类(union subclass)的继承层次中使用标识生成器策略(identity generator strategy)
再加上 这种方法下 生成的表多 而且字段有重复
查询时如果查询父类必须查询子类的表 修改父类的表 子类的表也要修改
既不支持多态查询也不支持多态关联
所以不推荐使用
但是还是要说一说
毕竟要让它跑起来嘛 再说 既然有这个方法 也是有它存在的理由
在调试中 ID的属性没有设置正确
这正是
不允许在联合子类(union subclass)的继承层次中使用标识生成器策略(identity generator strategy)
而且子类不该设置ID
看了很多资料
主要参考了一个和我遇到同样问题的帖子
地址
http://forum.hibernate.org/viewtopic.php?t=963635
最后让它可以运行了
Empolyee.hbm.xnl
修改成如下:
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" lazy ="true" >
< id name ="id" type ="long" column ="ID" >
< generator class ="hilo" >
< param name ="table" > hi_value </ param >
< param name ="column" > next_value </ param >
< param name ="max_lo" > 100 </ param >
</ generator >
</ id >
< property name ="name" column ="NAME" type ="string" />
< many-to-one name ="company"
column ="COMPANY_ID"
class ="ergal.Company" />
< union-subclass name ="ergal.HourlyEmployee" table ="HOURLY_EMPLOYEES" >
< property name ="rate" column ="RATE" type ="double" />
</ union-subclass >
< union-subclass name ="ergal.SalariedEmployee" table ="SALARIED_EMPLOYEES" >
< property name ="salary" column ="SALARY" type ="double" />
</ union-subclass >
</ class >
</ hibernate-mapping >
把generator 换成了 hilo
这样在hbm2ddl的时候又5个表
COMPANIES EMPLOYEES HOURLY_EMPLOYEE 和SALARIED_EMPLOYEE 多了个 Hi_Value
EMPLOYEES
1 - ID
2 - NAME
3 - COMPANY_ID
HOURLY_EMPLOYEE
1 - ID
2 - NAME
3 - COMPANY_ID
4 - RATE
SALARIED_EMPLOYEE
1 - ID
2 - NAME
3 - COMPANY_ID
4 - SALARY
Hi_Value
1 - next_value
测试代码
BusinessService.java
import java.util. * ;
import org.hibernate. * ;
import org.hibernate.cfg. * ;
public class BusinessService
... {
public static SessionFactory sessionFactory;
static
...{
try
...{
Configuration config=new Configuration();
sessionFactory=config.configure().buildSessionFactory();
}
catch(Exception e)
...{
e.printStackTrace();
}
}
public void saveEmployee(Employee employee)throws Exception
...{
Session session=sessionFactory.openSession();
Transaction tx=null;
try
...{
tx=session.beginTransaction();
session.save(employee);
tx.commit();
}
catch(Exception e)
...{
if(tx!=null)
...{
tx.rollback();
}
throw e;
}
finally
...{
session.close();
}
}
public Company loadCompany(Long id)throws Exception
...{
Session session=sessionFactory.openSession();
Transaction tx=null;
try
...{
tx=session.beginTransaction();
Company company=(Company)session.load(Company.class, id);
tx.commit();
return company;
}
catch(Exception e)
...{
if(tx!=null)
...{
tx.rollback();
}
throw e;
}
finally
...{
session.close();
}
}
public void test()throws Exception
...{
Company company=loadCompany(new Long(1));
double d1=150;
double d2=5000;
Employee he=new HourlyEmployee("Tom", company, d1);
Employee se=new SalariedEmployee("Mary", company, d2);
saveEmployee(he);
saveEmployee(se);
}
public void find()throws Exception
...{
Session session=sessionFactory.openSession();
Transaction tx=null;
try
...{
tx=session.beginTransaction();
List result=session.createQuery("from Employee").list();
for(Iterator it=result.iterator(); it.hasNext();)
...{
Employee c =(Employee)it.next();
System.out.println("Employee's ID :" + c.getId());
System.out.println("Employee's name :" + c.getName());
}
tx.commit();
}
catch(Exception e)
...{
if(tx!=null)
...{
tx.rollback();
}
throw e;
}
finally
...{
session.close();
}
}
public static void main(String[] args)throws Exception
...{
new BusinessService().find();
sessionFactory.close();
}
}
运行后我有疑问没有解决
查询和插入都没有问题
可以正常显示结果
但是
EMPLOYEE表始终是个空表
不像前面的映射 不管多少个表 怎么映射EMPLOYEE表都是存在的而且里面的值会自动和 子类的表同步
六 Table per concrete class, using implicit polymorphism每个具体类一个表 隐式多态
这就是实现 每个具体的类一张表的 另一种方法 隐式多态
代码如下
Employee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.Employee" table ="EMPLOYEES" >
< id name ="id" type ="long" column ="EMPLOYEE_ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< any name ="employee" meta-type ="string" id-type ="long" >
< meta-value value ="HE" class ="ergal.HourlyEmployee" />
< meta-value value ="SE" class ="ergal.SalariedEmployee" />
< column name ="EMPLOYEE_TYPE" />
< column name ="SUB_EMPLOYEE_ID" />
</ any >
</ class >
</ hibernate-mapping >
HourlyEmployee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.HourlyEmployee" table ="HOURLY_EMPLOYEES" polymorphism ="implicit" >
< id name ="id" type ="long" column ="HOURLY_EMPLOYEE_ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< property name ="rate" column ="RATE" type ="double" />
< many-to-one
name ="company"
column ="COMPANY_ID"
class ="ergal.Company"
/>
</ class >
</ hibernate-mapping >
SalariedEmployee.hbm.xml
<! DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
< hibernate-mapping >
< class name ="ergal.SalariedEmployee" table ="SALARUED_EMPLOYEES" polymorphism ="implicit" >
< id name ="id" type ="long" column ="SALARUED_EMPLOYEE_ID" >
< generator class ="native" />
</ id >
< property name ="name" column ="NAME" type ="string" />
< property name ="salary" column ="SALARY" type ="double" />
< many-to-one
name ="company"
column ="COMPANY_ID"
class ="ergal.Company"
/>
</ class >
</ hibernate-mapping >
运行hbm2ddl
产生表如下 4个
COMPANIES EMPLOYEES HOURLYEMPLOYEE 和SALARIEDEMPLOYEE
EMPLOYEES
1 - EMPLOYEE_ID
2 - NAME
3 - EMPLOYEE_TYPE
4 - SUB_EMPLOYEE_ID
5 - COMPANY_ID
HOURLYEMPLOYEE
1 - HOURLYEMPLOUYEE_ID
2 - NAME
3 - RATE
4 - COMPANY_ID
SALARIEDEMPLOYEE
1 - SALARIEDEMPLOYEE_ID
2 - NAME
3 - SALAR
4 - COMPANY_ID
测试代码有所变化
BusinessService.java
double d1 = 150 ;
HourlyEmployee he = new HourlyEmployee( " Tom " , d1, company);
saveEmployee(he);
Employee employee = new Employee();
employee.setEmployee(he);
saveEmployee(employee);
这样在储存时必须先持久化 一个子类 再用set方法加到父类中 再持久化父类
否则会抛出
[java] org.hibernate.TransientObjectException: object references an unsaved
transient instance - save the transient instance before flushing: ergal.HourlyE
mployee
这样的好处是什么?
还有这里使用了any
我要思考一下
最后一种
另外这里使用了any
简单记一下
<any> 是隐式的 我是这么理解的
从字面上看 就是这个属性可以关联到多个其他的对象
所以你可能更本看不出它是子类 接口 还是别的关联属性 在父类里显示为一个对象
对相应的类型做相应的标识
like this
<any name="payment" meta-type="string" id-type="long"> <meta-value value="CREDIT" class="CreditCardPayment"/> <meta-value value="CASH" class="CashPayment"/> <meta-value value="CHEQUE" class="ChequePayment"/> <column name="PAYMENT_CLASS"/> <column name="PAYMENT_ID"/> </any>
七 Mixing implicit polymorphism with other inheritance mappings隐式多态和其他继承映射混合使用
我要疯了
看官方文档吧 如果用到再仔细研究 这已经花了我两天的时间了
对这一映射还有一点需要注意。因为每个子类都在各自独立的元素<class> 中映射(并且Payment只是一个接口),每个子类可以很容易的成为另一 个继承体系中的一部分!(你仍然可以对接口Payment使用多态查询。)
<class name="CreditCardPayment" table="CREDIT_PAYMENT">
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
<generator class="native"/>
</id>
<discriminator column="CREDIT_CARD" type="string"/>
<property name="amount" column="CREDIT_AMOUNT"/>
...
<subclass name="MasterCardPayment" discriminator-value="MDC"/>
<subclass name="VisaPayment" discriminator-value="VISA"/>
</class>
<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
<id name="id" type="long" column="TXN_ID">
<generator class="native"/>
</id>
...
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="amount" column="CASH_AMOUNT"/>
...
</joined-subclass>
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
<key column="PAYMENT_ID"/>
<property name="amount" column="CHEQUE_AMOUNT"/>
...
</joined-subclass>
</class>
我们还是没有明确的提到Payment。 如果我们针对接口Payment执行查询 ——如from Payment—— Hibernate 自动返回CreditCardPayment(和它的子类,因为 它们也实现了接口Payment)、 CashPayment和Chequepayment的实例, 但不返回NonelectronicTransaction的实例。
限制
对“每个具体类映射一张表”(table per concrete-class)的映射策略而言,隐式多态的 方式有一定的限制。而<union-subclass>映射的限制则没有那 么严格。
下面表格中列出了在Hibernte中“每个具体类一张表”的策略和隐式多态的限制。
Inheritance strategy | Polymorphic many-to-one | Polymorphic one-to-one | Polymorphic one-to-many | Polymorphic many-to-many | Polymorphic load()/get() | Polymorphic queries | Polymorphic joins | Outer join fetching |
---|---|---|---|---|---|---|---|---|
table per class-hierarchy | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
table per subclass | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
table per concrete-class (union-subclass) | <many-to-one> | <one-to-one> | <one-to-many> (for inverse="true" only) | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | supported |
table per concrete class (implicit polymorphism) | <any> | not supported | not supported | <many-to-any> | s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult() | from Payment p | not supported | not supported |
终于差不多结束这一重要的章节
还有很多值得研究的 毕竟实际运用中 接口 抽象类 一对一 多对一 一对多 多对多 等等关系复杂
而且我们要为数据库的性能着想 选择最好的查询性能的映射方式 最节约储存空间的映射方式等等