hibernate下自定义字段的实现探讨

    最近做内部开发平台,有个需求,权限系统中用户的基本信息外还有很多扩展信息,不同的项目要有不同的信息需求,用hibernate实现了一下,这里再记录一下备查,最近一段时间比较抑郁,脑子总是晕乎乎的,文字混乱,见谅。
   公司程序员习惯于hibernate,平台集成了hibernate,h3支持动态组件“dynamic-component”,但是查一下dynamic-component,也必须在里面指定属性,网上搜索了一下发现了这篇文章
"用Hibernate实现领域对象的自定义字段",大体的意思就是配置文件中设置完dynamic-component,然后在运行时根据添加的字段重定义内存配置文件,再更新磁盘上的配置文件,最后更改数据库结构。这个方法比较恐怖,更改数据库结构这个需求我们不需要,如果我们也搞成这个样子,程序员一操作,平台的库结构就不可控了,特别是这个设置
<property name="hibernate.hbm2ddl.auto">update</property>
更新数据库的schema。这个方法还有一个问题,在集群处理的时候更新磁盘上的文件还有一个同步的问题。
    那能不能在系统初始化的时候,hibernate载入xml配置文件的时候动态插入修改呢,看了下hibernate的代码org.hibernate.cfg.AnnotationConfiguration下有个add的方法,断点测试,发现xml载入时要调用这个方法,思路就明显了,我们可以想办法重写这个方法,在载入xml时如果含有dynamic-component节点,那么我们就可以从另外的配置文件中取到此节点对应的扩展字段配置插入到这dynamic-component节点下,这样程序员在扩展user类的时候只需要数据库字段添加,form上字段添加,再配置dynamic-component节点的自定义扩展属性,那在自定义项目信息的时候不就ok了。
    我们的平台用spring进行集成,派生了org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean这个类,因此在AnnotationSessionFactoryBean这个派生类中初始化的时候调用父类setConfigurationClass()方法,吧自定义的AnnotationConfiguration设置进去,如果这个派生类叫AnnotationConfigurationEx,那么这个类可以这么写



import org.hibernate.MappingException;
import org.hibernate.cfg.AnnotationConfiguration;

public class AnnotationConfigurationEx extends AnnotationConfiguration{
    //private static final long serialVersionUID = 7945995403611791535L;
    protected void add(org.dom4j.Document doc) throws MappingException {
        super.add(DynamicComponentProccess(doc));
    }

}


这个DynamicComponentProccess(doc)方法里面就可以解析xml插入自定义扩展字段,我是这么写的
Element hbm = doc.getRootElement();
    
        List<Element> es = hbm.selectNodes("//class/dynamic-component");
        if(es.size()>0)
        {
            for(int i = 0;i<es.size();i++)
            {
                String className=es.get(i).getParent().attributeValue("name");
//这里从自己的配置文件中得到dynamic-component节点所在class的对应的扩展字段
                List<Element> l = getExtPropertyMap().get(className);
                if(l!=null)
                {
                    for(int j = 0;j<l.size();j++)
                    {
                        es.get(i).content().add(l.get(j));                    
                    }
                }
                else
                {
                    es.get(i).getParent().content().remove(es.get(i));
                }
            }
        }


        return doc;


这样hibernate在启动的时候就会载入自己需要的设置。扩展属性的配置文件是这么写的

<?xml version="1.0" encoding="UTF-8"?>
<class>
    <ext classnme="apps.ldap.authority.mould.swordUserImpl">
        <property name="email" column="email" type="string"/>
        <property name="telephoneNumber" column="telephoneNumber" type="string"/>
    </ext>
</class>


接下来我们要写mould和action里面的内容
我们定义了一个abstract的类加CustomizableEntity。需要自定义字段的mould都派生自它,这个类有4个方法,这段代码我完全抄录自文章“用Hibernate实现领域对象的自定义字段”,
public abstract class CustomizableEntity implements IEntity<String>,IAssignable {
    
    private Map<String,String> customProperties;

    public Map<String,String> getCustomProperties() {
         if (customProperties == null)
         customProperties = new HashMap<String, String>();        
         return customProperties;
    }
    
    public void setCustomProperties(Map<String,String> customProperties) {
         this.customProperties = customProperties;
    }
    
    public Object getValueOfCustomField(String name) {
         return getCustomProperties().get(name);
    }
    
    public void setValueOfCustomField(String name, String value) {
         getCustomProperties().put(name, value);
    }
}


很简单就是对自定义字段的操作。
action里面需要加一个方法自动对扩展字段赋值,我是这么写的

/**
     * 预处理扩展字段
     */
    @SuppressWarnings("unchecked")
    public static <T extends IEntity> void preProcessExtProperty(T entity,Map<String,String> values)
    {
        if(entity instanceof CustomizableEntity)
        {
            Map<String,List<Element>> extPropertyMap = DynamicComponentProccess.getExtPropertyMap();
            List<Element> es = extPropertyMap.get(entity.getClass().getName());
            if(es!=null)
            {
                for(int i =0;i<es.size();i++)
                {
                    String pName = es.get(i).attributeValue("name");
                    if (values.containsKey(pName))
                    {
                      ((CustomizableEntity) entity).setValueOfCustomField(pName, values.get(pName));
                    }
                    
                }
            }
        }
    }

判断如果是CustomizableEntity的派生类就把字段和扩展字段配置文件中字段对比,调用setValueOfCustomField方法,将扩展字段的值加进去。把这个方法放到action的父类中重写excute在里面调用就ok了,当然也可以手动调用,比较麻烦。

   这样我们的程序员在使用平台的过程中就可以自己定义user的扩展信息而不需要我们干预修改了。这里也只是只实现了一个string类型的字段值,其他类型的可以自己做扩展。spring里面怎么配置hibernate这里就不多说了。



[本日志由 英雄无敌 于 2010-03-16 05:44 PM 编辑]
上一篇: 值得讀者踏上的長路
下一篇: 进藏装备篇
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
相关日志:
评论: 0 | 引用: 0 | 查看次数: 11692
发表评论
昵 称:
密 码: 游客发言不需要密码.
邮 箱: 邮件地址支持Gravatar头像,邮箱地址不会公开.
网 址: 输入网址便于回访.
内 容:
验证码:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 5000 字 | UBB代码 关闭 | [img]标签 关闭