zoukankan      html  css  js  c++  java
  • 变态工作之修改hibernate让其支持null主键

    关于Hibernate主键包含null值的改动方案

    前言

    最近公司跟另外一个公司在合作一个项目,不幸被卷入其中。这几天做了一个变态的工作,就是客户死活就要复合主键能够支持null值,甚至扬言不惜修改hibernate,于是他如愿了。

    命题

    数据表中设置为主键的两个字段其中一个可以为空。

    分析

    经过分析,Hibernate3.0beta13支持可以为空的主键,但是之后就不再支持。同时,oracle也不支持可以为null的主键,在建表的过程中,只能建立unique索引。

    由此,建立可以为null的数据表主键的方法是一种非标准化的做法。就像参考文献中Hibernate作者所说的:

    Comment by Gavin King [04/Mar/05 02:04 PM]

    Hibernate 3 treats any key with a null value as null. This is reasonable because nulls in primary keys are completely evil and not allowed on most dbs.

    为了满足命题要求,我们需要修改Hibernate的代码。

    参考文献

    l         http://opensource.atlassian.com/projects/hibernate/browse/HHH-177

     

    步骤

    建立库表结构

    以下是用于实验的表结构代码:

    drop table CLASS1

    create table class1
        (field1 varchar2(10 char) not null,
        field2 varchar2(30 char) ,
        f3 number(10,0) not null,
        f4 varchar2(10 char) not null)

    create unique index uniq1 on CLASS1 (FIELD1 , FIELD2 );

     

    代码

    类定义的时候使用标准的Hibernate的复合主键结构。并且在映射配置文件中使用自定义的CRUD语句代替Hibernate的自动生成语句。

    文件Class1.java

    package com.chinainsurance.platform.service.impl.test;

     

    import java.io.Serializable;

     

    public class Class1 implements Serializable  {

        Class1ID id;

        Integer field3;

        String field4;

       

        public Integer getField3() {

           return field3;

        }

        public void setField3(Integer field3) {

           this.field3 = field3;

        }

        public String getField4() {

           return field4;

        }

        public void setField4(String field4) {

           this.field4 = field4;

        }

        public Class1ID getId() {

           return id;

        }

        public void setId(Class1ID id) {

           this.id = id;

        }

    }

     

    文件Class1ID.java

    package com.chinainsurance.platform.service.impl.test;

     

    import java.io.Serializable;

     

    public class Class1ID implements Serializable {

        String field1;

        String field2;    // nullable

     

       

       

        public String getField1() {

           return field1;

        }

        public void setField1(String field1) {

           this.field1 = field1;

        }

        public String getField2() {

           return field2;

        }

        public void setField2(String field2) {

           this.field2 = field2;

        }

        public boolean equals(Object arg0) {

           return super.equals(arg0);

        }

        public int hashCode() {

           return field1.hashCode();

        }

       

       

    }

    定义的hbm文件内容如下:

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

    <hibernate-mapping>

        <class name="com.chinainsurance.platform.service.impl.test.Class1" table="class1" lazy="false" >

           <composite-id name="id" class="com.chinainsurance.platform.service.impl.test.Class1ID" >

               <key-property name="field1" column="field1" type="java.lang.String" length="10" />

               <key-property name="field2" column="field2" type="java.lang.String" length="30"  />

           </composite-id>

           <property name="field3" column="f3" type="java.lang.Integer" length="20" not-null="true"/>

           <property name="field4" column="f4" type="java.lang.String" length="10" not-null="true"/>

          

           <loader query-ref="selectClass1"/>

     

           <sql-insert>INSERT INTO class1 (f3, f4, field1, field2) VALUES ( ?, ?, ?, ? )</sql-insert>

           <sql-update>UPDATE class1 SET f3=?, f4=? WHERE field1=? anD nvl(fielD2,'*')=nvl(?, '*')</sql-update>

           <sql-delete>DELETE FROM class1 where field1=? and nvl(fielD2,'*')=nvl(?, '*')</sql-delete>

     

        </class>

       

        <sql-query name="selectClass1">

           <return class="com.chinainsurance.platform.service.impl.test.Class1" >

               <return-property name="id">

                  <return-column name="field1"/>

                  <return-column name="field2"/>

               </return-property>

               <return-property name="field3" column="f3" />

               <return-property name="field4" column="f4" />

           </return>

          

           select * from class1 where field1=? and nvl(field2,'*')=nvl(?, '*')

        </sql-query>            

    </hibernate-mapping>

     

    修改的Hibernate源代码

    经过调试跟踪,发现不支持null主键的代码在org.hibernate.type.ComponentTypehydrate函数中,代码如下:

    if ( val == null ) {

        if (isKey) return null; //different nullability rules for pk/fk

    }

    else {

        notNull = true;

    }

    为此,我们需要把这一段代码修改为如下:

    if( val != null )

        notNull = true;

    编译Hiberante

    Hibernate的根目录下有build.bat,运行就可以编译生成hibernate3.jar,该文件也会在根目录下。

    测试

    使用如下的测试用例来测试以下结果:

     

    package com.chinainsurance.platform.service.impl.test;

     

    import java.util.List;

     

    import org.springframework.orm.hibernate3.HibernateTemplate;

    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

     

    import com.chinainsurance.platform.service.helper.TaskServiceHelper;

     

    import junit.framework.TestCase;

     

    /*

    drop table CIUSER.CLASS1

    create table class1 (field1 varchar2(10 char) not null, field2 varchar2(30 char) , f3 number(10,0) not null, f4 varchar2(10 char) not null)

    create unique index uniq1 on CIUSER.CLASS1 (FIELD1 , FIELD2 );

    */

    public class TestClasses extends TestCase {

     

        HibernateTemplate dao;

       

        public TestClasses()

        {

           TaskServiceHelper.context = TestUtil.getContext();

           HibernateDaoSupport t = (HibernateDaoSupport) TaskServiceHelper.getDao("reportJobDao");

           dao = t.getHibernateTemplate();

        }

        protected void setUp() throws Exception {

           super.setUp();

        }

     

        protected void tearDown() throws Exception {

           super.tearDown();

           try{   clearClass1();    }catch(Exception e){}

        }

     

        private void clearClass1()

        {

           List list = dao.loadAll(Class1.class);

           for(int i = 0; i < list.size(); ++i)

           {

               dao.delete(list.get(i));

           }

        }

       

        private Class1 insertClass1()

        {

           Class1 obj1 = createClass1();

           try{

           dao.save(obj1);

           }

           catch(Exception e)

           {

               // System.out.println(e.toString());

           }

          

           return obj1;

        }

       

        private Class1 createClass1()

        {

           Class1 obj1 = new Class1();

           Class1ID id = new Class1ID();

           id.setField1("c1f1");

           id.setField2(null);

           obj1.setId(id);

          

           obj1.setField3(new Integer(1));

           obj1.setField4("c1f4");

     

           return obj1;

        }

       

        public void testClass1Add()

        {

           System.out.println("testClass1Add");

           dao.save(createClass1());

           clearClass1();

        }

     

        public void testClass1Delete()

        {

           System.out.println("testClass1Delete");

           Class1 obj1 = insertClass1();

          

           dao.delete(obj1);

        }

     

        public void testClass1Load()

        {

           System.out.println("testClass1Load");

           insertClass1();

          

           Class1ID id = new Class1ID();

           id.setField1("c1f1");

           id.setField2(null);

     

           Class1 obj1 = (Class1) dao.load(Class1.class, id);

           assertEquals(obj1.getId().getField1(), "c1f1");

           assertNull(obj1.getId().getField2());

           clearClass1();

        }

     

        public void testClass1Update()

        {

           System.out.println("testClass1Update");

          

           Class1 obj1 = insertClass1();

       

           obj1.setField4("ok");

           dao.update(obj1);

        }

     

        public void testClass1Find()

        {

           System.out.println("testClass1Find");

           insertClass1();

           List list = dao.find("from Class1 as c where c.id.field2 is null");

           assertTrue(list.size() > 0);

           clearClass1();

        }

       

        public void testClass1LoadAll()

        {

           System.out.println("testClass1LoadAll");

           insertClass1();

           List list = dao.loadAll(Class1.class);

           //assertTrue(list.size() > 0);

           //clearClass1();

           System.out.println("size = " + list.size());

           for(int i = 0; i < list.size(); ++i)

           {

               Class1 cls = (Class1)list.get(i);

               System.out.println("" + cls.getId().getField1() + cls.getId().getField2());

           }

          

           clearClass1();

        }     

       

    }

  • 相关阅读:
    基于vue2.0 +vuex+ element-ui后台管理系统:包括本地开发调试详细步骤
    require.js实现js模块化编程(二):RequireJS Optimizer
    require.js实现js模块化编程(一)
    树型权限管理插件:jQuery Tree Multiselect详细使用指南
    表格组件神器:bootstrap table详细使用指南
    后台管理系统中的重点知识大全
    Ajax最详细的参数解析和场景应用
    npm常用命令小结
    详解javascript,ES5标准中新增的几种高效Object操作方法
    git入门学习(二):新建分支/上传代码/删除分支
  • 原文地址:https://www.cnblogs.com/BigTall/p/446401.html
Copyright © 2011-2022 走看看