2016-03-21 14 views
0

Son kayıttan bu yana hiçbir değişiklik yapılmadığında birleştiğim herhangi bir varlığı kaydetmemek için bir yöntem arıyorum. Bunun, Envers'in normal davranışı olması gerektiğine karar verdim (herhangi bir değişiklik yoksa denetim yok).Hazırda bekletme yok bir değişiklik oluştururken bir kayıt oluşturma

Öğeler yalnızca @Audited ek açıklamalarına sahiptir, ancak son denetimden beri değişiklik olmadığında bile denetime devam ederler. Bu benim persitence.xml konfigürasyonu: Ben bu Hibernate Envers: Auditing an object, calling merge on it, gives an audit record EVERY time even with no change? bulduk ama cevap yok

<property name="org.hibernate.envers.revision_field_name" value="revision" /> 
<property name="org.hibernate.envers.revision_type_field_name" value="revision_type" /> 
<property name="org.hibernate.envers.revision_on_collection_change" value="false"/> 
<property name="org.hibernate.envers.store_data_at_delete" value="true"/> 

.

Bazı equals()/hascode() yöntemlerim yalnızca kimlikler için (birincil anahtarlar) sınanıyor, ancak bunun nasıl ilişkilendirilebileceği konusunda bir konu bulamadım.

Ayrıca, hangi alanın değiştiğini görmek için yeni bir parametre olduğunu gördüm, ancak bunun benim de sorunumla ilgili olduğunu sanmıyorum.

Eğer önemliyse Postgresql kullanıyorum.

Bu davranış için herhangi bir fikir var mı? Şu an için sahip olduğum tek çözüm, varlığı entityManager aracılığıyla almak ve bunları karşılaştırmaktır (eğer buna göre bazı yansıma tabanlı API kullanacağım).

cevap

3

Sorun, uygulamadan değil, kodun kendisinden kaynaklandı. Bizim girişler, her bir birleşme() 'de geçerli tarihte ayarlanmış bir alan "lastUpdateDate" vardır. Karşılaştırma, birleştirme işleminden sonra gerçekleştirilir, böylece bu alan son revizyondan bu yana değişmiştir. meraklı olanlar için

, sürümleri arasındaki değişiklikler oldState ve newState arasında herhangi bir değişim olursa true döndürür (en azından evers 4.3.5.Final üzerine) org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper.map() değerlendirilir. Karşılaştırılan özelliklere bağlı olarak belirli bir mapper kullanır.


DÜZENLEME: Sorunu nasıl çözdüğümü buraya koyacağım, ancak Dagmar'ın çözümü de kullanılabilir. Ancak benimki biraz daha zor ve kirli olabilir.

Envers'in EnversPostUpdateEventListenerImpl numarasını The official documentation ve various SO answers numaralı telefonlarda kullandım: Ben oluşturdum ve Envers'in onu kullanmak için zorladım.

@Override 
public void onPostUpdate(PostUpdateEvent event) { 
    //Maybe you should try catch that ! 
    if (event.getOldState() != null) { 
     final EntityPersister entityPersister = event.getPersister(); 
     final String[] propertiesNames = entityPersister.getPropertyNames(); 

     for (int i = 0; i < propertiesNames.length; ++i) { 
      String propertyName = propertiesNames[i]; 
      if(checkProperty(propertyName){ 
       event.getOldState()[i] = event.getState()[i]; 
     } 
    } 
    // Normal Envers processing 
    super.onPostUpdate(event); 
} 

Benim checkProperty(String propertyName) (yani onlar bizim app nasıl çünkü propertyName.endsWith("lastUpdateDate")) bir güncellemenin tarihi özelliği ise sadece kontrol etti. İşin sırrı, eski devleti yeni duruma ayarlıyorum, eğer bu benim varlığımdaki tek değiştirilmiş alan ise, onu denetlemez (envers ile devam ettirmek). Ancak, değiştirilen başka alanlar varsa Envers, bu düzeltilmiş alanlar ve doğru lastUpdateDate ile tüzel kişiyi denetler.

Ayrıca, OldState'in ss: dd: ss ile ayarlanmadığı (yalnızca sıfırın) olduğu ve yeni durumun saat ayarı ile aynı gün olduğu bir sorunum da vardı. Bu yüzden benzer bir hile kullandı:

Date oldDtEffet = (Date) event.getOldState()[i]; 
Date newDtEffet = (Date) event.getState()[i]; 
if(oldDtEffet != null && newDtEffet != null && 
     DateUtils.isDateEqualsWithoutTime(oldDtEffet,newDtEffet)){ 
    event.getOldState()[i] = event.getState()[i]; 
} 

(Not:. Eğer onlar juste olsa bile, TÜM olay dinleyicileri reimplement Envers sınıfları miras gerekir, hiçbir geri dönüş yoktur org.hibernate.integrator.spi emin olun.Entegratör sizin uygulamanızda)

+0

Kendi sorunuza verilen yanıt için teşekkürler! Benzer bir sorunla karşı karşıyayım ve güncellemeyi orijinal ile karşılaştırarak bir sorun yaşıyorum. İzleme sütunlarımı ayarlamak için bir Hibernate MergeEventListener kullanıyorum ancak büyük sorunum MergeEvent "orijinal" nesnesinin "varlık" ile aynı olmasıdır. Yani Yönetilen bir nesne olduğu için zaten güncellemeler uygulandı. Lütfen çözümünüzü paylaşır mısınız? – Dagmar

+0

Üzgünüz, yorumunuzu gönderdiğinizde müsait değildim. Bir çözüm bulduğuna sevindim, cevabımı, sorunu özmek için yaptığım şeyi de içerecek şekilde düzenleyeceğim, ama çözümünüz de iyi görünüyor. – Asoub

0

İyi haber şu ki Hibernate Envers beklendiği gibi çalışır - denetlenebilir bir özellik değiştirilmediği sürece sürümler (AUD tablolarına girişler) oluşturulmaz. Ancak, bizim uygulamada, her varlık kaydında izleme alanlarını (lastUpdated, lastUpdatedBy) güncelleyen bir MergeEventListener uygulamıştık. Bu, Envers'in varlıkta herhangi bir değişiklik yapılmadığında bile yeni bir sürüm oluşturmasına neden oldu.

çözeltisi (bizim için) sonunda oldukça basitti - hazırda Müdahale ve Olaylar nasıl kullanılacağına dair bir örnek kullanılarak: Bizim sınıf EmptyInterceptor ve genişleten bir sınıf ile PersistEventListener ve MergeEventListener uygulayan yerini

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/events.html onFlushDirty ve onSave yöntemlerini geçersiz kılar.

public interface ModificationTracker { 

    public Date getLastUpdated(); 

    public Date getCreatedDate(); 

    public User getCreatedBy(); 

    public User getLastUpdatedBy(); 

    public void setLastUpdated(Date lastUpdated); 

    public void setCreatedDate(Date createdDate); 

    public void setCreatedBy(User createdBy); 

    public void setLastUpdatedBy(User lastUpdatedBy); 
} 

Ayrıca bu sorunu çözmek mümkün olmalıdır: Hazırda JPA sebat birimi

<?xml version="1.0" encoding="UTF-8"?> 
<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 

    <persistence-unit name="myapplication" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <properties> 
      <property name="hibernate.ejb.interceptor" value="org.myapplication.interceptor.EntitySaveInterceptor" />   
      <property name="hibernate.hbm2ddl.auto" value="none"/> 
      <property name="hibernate.show_sql" value="false"/> 
     </properties> 
    </persistence-unit> 

</persistence> 

Ve şeyiyle için EntitySaveInterceptor kadar takma

public class EntitySaveInterceptor extends EmptyInterceptor { 

    @Override 
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { 
    setModificationTrackerProperties(entity); 
    return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types); 
    } 

    @Override 
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { 
    setModificationTrackerProperties(entity); 
    return super.onSave(entity, id, state, propertyNames, types); 
    } 

    private void setModificationTrackerProperties(Object object) { 
    if (SecurityContextHolder.getContext() != null && SecurityContextHolder.getContext().getAuthentication() != null) { 
     Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
     if (principal != null && principal instanceof MyApplicationUserDetails) { 
     User user = ((MyApplicationUserDetails) principal).getUser(); 
     if (object instanceof ModificationTracker && user != null) { 
      ModificationTracker entity = (ModificationTracker) object; 
      Date currentDateTime = new Date(); 
      if (entity.getCreatedDate() == null) { 
      entity.setCreatedDate(currentDateTime); 
      } 
      if (entity.getCreatedBy() == null) { 
      entity.setCreatedBy(user); 
      } 
      entity.setLastUpdated(currentDateTime); 
      entity.setLastUpdatedBy(user); 
     } 
     } 
    } 
    } 
} 

, burada ModificationTracker arayüzü PreUpdateEventListener'un bir uygulaması kullanılarak, ModificationTracker değerlerini ayarlamak için bu dinleyici yalnızca nesne olduğunda tetiklenir. kirli.

İlgili konular