2012-07-17 129 views
2

框架:春季3與Hibernate 3休眠。實體變化修訂歷史

數據庫:Oracle 11

要求:我們的應用程序將有事件的對象。這些Event對象中的每一個都是一組實體屬性(表列)的封裝。因此,無論何時在我們的系統中更新任何實體,我們都需要確保對實體所做的更改是否是任何Event對象的一部分,如果是,則需要將此信息與記錄的記錄一起存儲在數據庫中實際變化。

解決方案(據我所知):

  1. 使用像Hibernate Envers一個完全成熟的審計框架和寫周圍的審計表查詢功能的小包裝,來完成我需要什麼。一個問題是,hibernate Envers是否有一種簡單的方法來提供兩個修訂之間的變化。

  2. 使用自定義註釋將屬性標記爲屬於事件,並使用AOP作爲保存操作的一部分監視對這些屬性的更改並調用自定義寫入操作。

我更喜歡第二個想法。

請分享你的意見\想法,以儘可能完成這件事。是否有針對此類問題的現有解決方案?

回答

2

我在項目中有類似的需求,我想在保存之前拍攝複雜對象圖的快照。

溶液我已經申請是 1)開發的定製註釋@Archivable與某些屬性等抵消,忽略,一部開拓創新,setArchiveFlag

2)寫入的Hiberante深拷貝機的工具,它創建的對象的副本,並插入到相同的表。深層克隆人使用簡單的技巧searlize然後desearlize對象,這將創建新的實例,然後將id和版本設置爲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; 
    } 
    }