【问题标题】:Hibernate. Entity change\revision history休眠。实体更改\修订历史
【发布时间】:2012-07-16 18:31:57
【问题描述】:

框架:Spring 3 和 Hibernate 3。

数据库:Oracle 11

要求:我们的应用程序将具有事件对象。这些 Event 对象中的每一个都是一组 Entity 属性(表列)的封装。因此,无论何时在我们的系统中更新任何实体时,我们都需要确保对实体所做的更改是否属于任何事件对象,如果是,我们需要将此信息与记录的副本一起存储在数据库中实际变化。

解决方案(据我所知):

  1. 使用完整的审计框架(如 Hibernate Envers)并围绕审计表查询功能编写一个小型包装器,以完成我需要的工作。一个问题是,hibernate Envers 是否有一种简单的方法来提供两个版本之间的变化。

  2. 使用自定义注解将属性标记为属于某个事件,并使用 AOP 监视对这些属性的更改,作为保存操作的一部分并调用自定义写入操作。

我更喜欢第二个想法。

请就完成此任务的最佳方法分享您的意见\想法。这类问题有现成的解决方案吗?

【问题讨论】:

    标签: hibernate audit-logging


    【解决方案1】:

    我在项目中有类似的要求,我想在保存之前拍摄复杂对象图的快照。

    我应用的解决方案是 1) 开发了自定义注解@Archivable,具有某些属性,如nullify、ignore、orignal、setArchiveFlag

    2) 编写了 hiberante 深度克隆实用程序,它创建对象的副本并插入到同一个表中。深度克隆器适用于简单的技巧 searlize 然后反序列化对象,这将创建新实例,然后将 id 和 version 设置为 null。

    3) 在实体拦截器中使用克隆器实用程序来决定天气是否存档。

    下面是其中的一些代码。

    @Retention(RetentionPolicy.RUNTIME)
    @Target( { ElementType.TYPE })
    public @interface Archivable {
    
        /** This will mark property as null in clone */
        public String[] nullify() default {};
    
        /**
         * If property is archivable but not from enclosing entity then specify as
         * ignore.
         */
        public String[] ignore() default {};
    
        /**
         * sets original reference to clone for back refer data. This annotation is
         * applicable to only root entity from where archiving started.
         * 
         * @return
         */
        public String original() default "";
    
        /**
         * if marks cloned entity to archived, assumes flag to be "isArchived". 
         * @return
         */
        public boolean setArchiveFlag() default false;
    }
    
    
    @Component
    public class ClonerUtils {
    
        private static final String IS_ARCHIVED = "isArchived";
        @Autowired
        private SessionFactory sessionFactory;
    
        public Object copyAndSave(Serializable obj) throws Exception {
            List<BaseEntity> entities = new ArrayList<BaseEntity>();
            Object clone=this.copy(obj,entities);
            this.save(clone, entities);
            return clone;
        }
    
        public Object copy(Serializable obj,List<BaseEntity> entities) throws Exception{
            recursiveInitliaze(obj);
            Object clone = SerializationHelper.clone(obj);
            prepareHibernateObject(clone, entities);
            if(!getOriginal(obj).equals("")){
                PropertyUtils.setSimpleProperty(clone, getOriginal(obj), obj);
            }
            return clone;
        }
    
    
        private void save(Object obj,List<BaseEntity> entities){
            for (BaseEntity baseEntity : entities) {
                sessionFactory.getCurrentSession().save(baseEntity);
            }
        }
    
        @SuppressWarnings("unchecked")
        public void recursiveInitliaze(Object obj) throws Exception {
            if (!isArchivable(obj)) {
                return;
            }
            if(!Hibernate.isInitialized(obj))
                Hibernate.initialize(obj);
            PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
            for (PropertyDescriptor propertyDescriptor : properties) {
                Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
                if (origProp != null && isArchivable(origProp) && !isIgnore(propertyDescriptor, obj)) {
                    this.recursiveInitliaze(origProp);
                }
                if (origProp instanceof Collection && origProp != null) {               
                    for (Object item : (Collection) origProp) {
                        this.recursiveInitliaze(item);
                    }
                }
            }
        }
    
    
        @SuppressWarnings("unchecked")
        private void prepareHibernateObject(Object obj, List entities) throws Exception {
            if (!isArchivable(obj)) {
                return;
            }
            if (obj instanceof BaseEntity) {
                ((BaseEntity) obj).setId(null);
                ((BaseEntity) obj).setVersion(null);
                if(hasArchiveFlag(obj)){
                    PropertyUtils.setSimpleProperty(obj, IS_ARCHIVED, true);
                }
                entities.add(obj);
            }
            String[] nullifyList = getNullifyList(obj);
            for (String prop : nullifyList) {
                PropertyUtils.setProperty(obj, prop, null);
            }
            PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
            for (PropertyDescriptor propertyDescriptor : properties) {
                if (isIgnore(propertyDescriptor, obj)) {
                    continue;
                }
                Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());         
                if (origProp != null && isArchivable(origProp)) {
                    this.prepareHibernateObject(origProp, entities);
                }   
                /**  This code is for element collection */
                if(origProp instanceof PersistentBag){
                    Collection elemColl=createNewCollection(origProp);
                    PersistentBag pColl=(PersistentBag) origProp;
                    elemColl.addAll(pColl.subList(0, pColl.size()));
                    PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), elemColl);
                    continue;
                }
                if (origProp instanceof Collection && origProp != null) {
                    Collection newCollection  = createNewCollection(origProp);
                    PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), newCollection);
                    for (Object item : (Collection) origProp) {
                        this.prepareHibernateObject(item, entities);
                    }
                }
            }
        }
    
    
    
        @SuppressWarnings("unchecked")
        private Collection createNewCollection(Object origProp) {
            try {
                if(List.class.isAssignableFrom(origProp.getClass()))
                    return new ArrayList((Collection)origProp);
                else if(Set.class.isAssignableFrom(origProp.getClass()))
                        return new HashSet((Collection)origProp);
                else{
                    Collection tempColl=(Collection) BeanUtils.cloneBean(origProp);
                    tempColl.clear();
                    return tempColl;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return new ArrayList();     
        }
    
        private boolean isIgnore(PropertyDescriptor propertyDescriptor,Object obj){
            String propertyName=propertyDescriptor.getName();
            String[] ignores=getIgnoreValue(obj);
            return ArrayUtils.contains(ignores, propertyName);
        }
    
        private String[] getIgnoreValue(Object obj) {
            String[] ignore=obj.getClass().getAnnotation(Archivable.class).ignore();
            return ignore==null?new String[]{}:ignore;
        }
    
        private String[] getNullifyList(Object obj) {
            String[] nullify=obj.getClass().getAnnotation(Archivable.class).nullify();
            return nullify==null?new String[]{}:nullify;
        }
    
        public boolean isArchivable(Object obj) {
            return obj.getClass().isAnnotationPresent(Archivable.class);
        }
    
    
        private String getOriginal(Object obj) {
            String original=obj.getClass().getAnnotation(Archivable.class).original();
            return original==null?"":original;
        }
    
        private boolean hasArchiveFlag(Object obj) {        
            return obj.getClass().getAnnotation(Archivable.class).setArchiveFlag();
        }
    
        @SuppressWarnings({ "unchecked", "unused" })
        private Collection getElemColl(Object obj, Object origProp) {
            Collection elemColl=createNewCollection(origProp);
            for (Object object : (Collection)origProp) {
                elemColl.add(object);
            }
            return elemColl;
        }
    
        @SuppressWarnings("unused")
        private boolean isElementCollection(Object obj, String name) {
            try {
                Annotation[] annotations=obj.getClass().getDeclaredField(name).getAnnotations();
                for (Annotation annotation : annotations) {
                    if(annotation.annotationType() == ElementCollection.class)
                        return true;
                }
            } catch (Exception e) {
                e.printStackTrace();            
            }
            return false;
        }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 2018-09-22
      • 2015-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多