继承映射

来源:互联网 发布:死神的精确度 知乎 编辑:程序博客网 时间:2024/06/05 09:21
 

                                      集合映射

在list中不能放弃关联关系,如果放弃了关联关系就没法维护插入的员工的顺序了

在set集合中才可以放弃关联关系

在一对多和多对多才可以放弃关联关系 inverse的默认值为false,既不放弃关联关系

 

继承映射

继承对象模型是is a(是一个)的关系,在关系模型中,实体间只有has a(有一个)的关系,也就是说,继承在对象模型和关系模型上是不匹配的

 

方式一:整个的继承的体系就用一张表

这种映射方案在性能和简单性方面都很好,在多态和非多态的查询上也表现的很好。是继承映射中使用比较广泛的方案。子类中属性的值必须是可以为空的,这种映射方案的关系模型表设计也违背了第三范式

优点:因为在一张表中查询,所以效率比较高

缺点:关系模型不是很合理,里面存在的大量字段都是空的

 

设计一张表employee

Id   name      depart_id       type       skill        sell

                                           0         null         null

                                           1           coding  null

                                           2       null    100

 

type【0,表示普通员工    1,技术员     2,销售员】    

<!-- 继承映射中,employee子类的映射 -->

       <subclass name="Skiller">

           <property name="skill"/>

       </subclass>

       <subclass name="Sales">

           <property name="sell"/>

       </subclass>

Type-----鉴别器,不是给java代码去用的,是给hibernate用的,在映射文件中定义鉴别器:

<hibernate-mapping

    package="com.hbsi.domain">

 

    <class name="Employee" table="employee" discriminator-value="0">

       <id name="id" column="id">

       <!-- native自动增长   根据不同的底层数据库选择产生不同的策略 -->

           <generator class="native"/>

       </id>

           <!-- 定义鉴别器,缺省的类型是字符串类型 -->

       <discriminator column="type" type="int"/>

       <property name="name"/>

       <!-- 映射文件的属性就不能用property -->

       <!-- 用many-to-one实现多对一的映射 -->

       <!-- 如果不带foreign-key属性,它会默认使用depart ,如果带上这个属性,可以知道另一张表 -->

       <many-to-one name="depart" column="depart_id"/>

 

       <!-- 继承映射中,employee子类的映射 -->

       <subclass name="Skiller" discriminator-value="1">

           <property name="skill"/>

       </subclass>

       <subclass name="Sales" discriminator-value="2">

           <property name="sell"/>

       </subclass>

    </class>

</hibernate-mapping>

鉴别器的位置不满足要求时会报错,鉴别器本身的位置是比较靠前的

 

方式二:每个子类一张表

这种方案是把对象模型上的继承关系表示为关系模型中的外键关联,继承结构中的每个类和子类(包括抽次类和接口)都有一张对应的数据库表

在父类对应的数据库中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只存储子类中所特有的属性映射的字段值;子类与父类,通过相同的主键值来关联

模式设计合理,但效率不高

每个子类一张表,存放子类所特有的属性

Employee                 skiller                  sales

Id name depart_id     emplouee_id skill      employee_id sell

 

<class name="Employee" table="employee">

    <id name="id" column="id">

       <generator class="native"/>

    </id>

    <property name="name"/>

    <many-to-one name="depart" column="depart_id"/>

   

    <!-- 子类的映射,子类的特殊属性映射为一张表 -->

    <joined-subclass name="Skiller" table="skiller">

       <key column="employee_id"/>

       <property name="skill"/>

    </joined-subclass>

   

    <joined-subclass name="Sales" table="sales">

       <key column="employee_id"/>

       <property name="sell"/>

    </joined-subclass>

</class>

 

方式三:混合使用一个类继承一张表和每个子类一张表,既以上两种方式的混合

<class name="Employee" table="employee" discriminator-value="0">

    <id name="id" column="id">

       <generator class="native"/>

    </id>

    <!--   设定鉴别器 --> 

    <discriminator column="type" type="integer"/>

    <property name="name"/>

    <many-to-one name="depart" column="depart_id"/>

    <subclass name="Skiller" discriminator-value="1">

       <property name="skill"/>

    </subclass>

    <subclass name="Sales" discriminator-value="2">

       <join table="sales">

           <key column="employee_id"/>

           <property name="sell"/>

       </join>

    </subclass>

</class>

抛异常原因:配置文件中是create,删除销售表时可以删,但是删除员工表时,因为技术表中的外键是员工表中的主键,所有员工表没法删除,所有会抛异常。

解决办法:1、手动的把那几张表删除。2、把配置文件中的create改为update

 

 

方式四:每个具体类是一张完整的表(union-subclass),保存子类完整的信息

这种策略是针对每个具体对应的一张表,而且这个表的信息是完备的,它包含所有从父类继承下来的属性映射的字段和自己的属性映射的字段。

注意:如果父类是具体类,还需要另外一张表来存放这个类的实例

 

<class name="Employee" table="employee1">

    <id name="id" column="id">

    <!-- 高低位的主键生成器,在hibernate生成主键时产生一张表存储,在程序运行时产生地位,将高位与地位连接起来,产生一个唯一的主键 -->

       <generator class="hilo"/>

    </id>

    <property name="name"/>

    <many-to-one name="depart" column="depart_id"/>

    <union-subclass name="Skiller" table="skiller1">

       <property name="skill"/>

    </union-subclass>

    <union-subclass name="Sales" table="sales1">

       <property name="sell"/>

    </union-subclass>

</class>

 

抛异常:主键的生成器不能用native

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Exception in thread "main" java.lang.ExceptionInInitializerError

    at com.hbsi.test.TestExtends.add(TestExtends.java:26)

    at com.hbsi.test.TestExtends.main(TestExtends.java:20)

Caused by: org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.hbsi.domain.Sales

    at org.hibernate.persister.entity.UnionSubclassEntityPersister.<init>(UnionSubclassEntityPersister.java:90)

    at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:90)

    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:286)

    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1872)

    at com.hbsi.hibernate.utils.HibernateUtil.<clinit>(HibernateUtil.java:19)

    ... 2 more

 

抛异常:解决办法,把数据库中原有的表删除就好了

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Hibernate: insert into department (name) values (?)

Hibernate: insert into employee (name, depart_id, id) values (?, ?, ?)

Exception in thread "main" org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update

    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)

    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)

    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)

    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)

    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)

    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)

    at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)

    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2411)

    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)

    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)

    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)

    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)

    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)

    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)

    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)

    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)

    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)

    at com.hbsi.test.TestExtends.add(TestExtends.java:53)

    at com.hbsi.test.TestExtends.main(TestExtends.java:20)

Caused by: java.sql.BatchUpdateException: Field 'type' doesn't have a default value

    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1669)

    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1085)

    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)

    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)

    ... 16 more

 

在实际开发中,如何选择合适的方案:

1、  如果不需要对态查询:使用每个具体类的一张表

2、  一定要使用多态查询:子类中的属性相对较少,使用每个继承层次一张表

3、  子类中的属性较多,使用每个子类一张表

4、  简单的问题一般选择每个继承层次一张表,复杂的案例一般选择每个子类一张表

原创粉丝点击