These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 45 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: Wed Dec 08, 2004 9:31 pm 
Beginner
Beginner

Joined: Sun Nov 07, 2004 4:19 pm
Posts: 38
Let me iterate an important question that StanAccy asked.

Why doesn't the onFlushDirty pass in only the modified list instead of all the properties?

If onFlushDirty is not appropriate then create another routine that would.

Dino


Top
 Profile  
 
 Post subject: Re: update(), Hibernate has no snapshot
PostPosted: Mon Jan 17, 2005 3:40 pm 
Newbie

Joined: Mon Jan 17, 2005 3:29 pm
Posts: 1
gavin wrote:
If you use update(), Hibernate has no snapshot. That is the nature of update()


If update() is unable to populate previousState of the Interceptor.onFlushDirty() method, witch is the best alternative? Load the previous object in DB with a second session to compare? It must be a better way, otherwise, what's the use of the previousState[] parameter?

Thanks for your time,
Mathieu


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 17, 2005 4:08 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
If you want to select before update, set select-before-update=true


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 13, 2005 11:11 pm 
Newbie

Joined: Sun Feb 13, 2005 10:52 pm
Posts: 3
Does the history interceptor work or not?

When I tried it out I get all the appropriate debugging indicating that the interceptor is creating history entries however the history entries are never saved to the database. It seems postFlush is too late to add them to the object.

Has anyone got this to work? Is there another way of implementing this type of audit logging?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 21, 2005 10:36 pm 
Beginner
Beginner

Joined: Sat Jan 22, 2005 9:11 am
Posts: 35
Location: London
If you want to compare old with new values, Hibernate needs to know the old values. I think Gavin means that update() is used primarily to make transient instances persistent and so old values will obviously not be there (unless you specify select-before-update of course).

Explicitly calling update() will not be necessary if you just load your objects, modify them and then let Hibernate persist the changes automatically when you tx.commit().


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 20, 2005 9:15 pm 
Regular
Regular

Joined: Tue Nov 09, 2004 5:15 pm
Posts: 100
I'm using the HibernateInterceptor code from the wiki page. While testing this code, i'm getting the following exception in the pre-flush.

Code:
[junit] ERROR - SessionImpl.execute(2375) | Could not synchronize database state with session
    [junit] net.sf.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.apple.ermt.persistence.audit.HistoryEntry
    [junit]     at net.sf.hibernate.impl.SessionImpl.throwTransientObjectException(SessionImpl.java:2764)
    [junit]     at net.sf.hibernate.impl.SessionImpl.getEntityIdentifierIfNotUnsaved(SessionImpl.java:2756)
    [junit]     at net.sf.hibernate.type.EntityType.getIdentifier(EntityType.java:66)
    [junit]     at net.sf.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:47)
    [junit]     at net.sf.hibernate.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:384)
    [junit]     at net.sf.hibernate.collection.Set.writeTo(Set.java:226)
    [junit]     at net.sf.hibernate.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:523)
    [junit]     at net.sf.hibernate.impl.ScheduledCollectionRecreate.execute(ScheduledCollectionRecreate.java:23)
    [junit]     at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2414)
    [junit]     at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2371)
    [junit]     at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236)
    [junit]     at org.springframework.orm.hibernate.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:214)
    [junit]     at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:201)
    [junit]     at org.springframework.orm.hibernate.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:341)
    [junit]     at com.apple.ermt.dao.hibernate.HibernateProjectDAO.saveProject(HibernateProjectDAO.java:38)
    [junit]     at com.apple.ermt.dao.ProjectDAOTest.testSaveProject(ProjectDAOTest.java:38)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    [junit]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    [junit]     at java.lang.reflect.Method.invoke(Method.java:324)
    [junit]     at junit.framework.TestCase.runTest(TestCase.java:154)
    [junit]     at junit.framework.TestCase.runBare(TestCase.java:127)
    [junit]     at junit.framework.TestResult$1.protect(TestResult.java:106)
    [junit]     at junit.framework.TestResult.runProtected(TestResult.java:124)
    [junit]     at junit.framework.TestResult.run(TestResult.java:109)
    [junit]     at junit.framework.TestCase.run(TestCase.java:118)
    [junit]     at junit.framework.TestSuite.runTest(TestSuite.java:208)
    [junit]     at junit.framework.TestSuite.run(TestSuite.java:203)
    [junit]     at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:289)
    [junit]     at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:656)
    [junit]     at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:558)
    [junit] Testsuite: com.apple.ermt.dao.ProjectDAOTest



I've modified the preFlush code to use a new TEMP session.



Code:
public void postFlush(Iterator it) throws CallbackException {
       log.debug("Post-Flush");
       while (it.hasNext()) {
         Object obj = it.next();
         if (!(obj instanceof Historizable)) {
           continue;
         }
         Historizable h = (Historizable) obj;
         Set newEntries = (Set) histories.get(h);
         if (newEntries == null) {
           continue;
         }
        
         h.getHistoryEntries().addAll(newEntries);
         log.debug("history entry size: " + h.getHistoryEntries().size());
        
         for(Iterator itr = h.getHistoryEntries().iterator(); itr.hasNext(); ) {
              HistoryEntry historyEntry = (HistoryEntry)itr.next();
            Session session = null;
            try {
               session = sessionFactory.openSession();
              session.save(historyEntry);
              session.flush();
            } catch(Exception e) {
                throw new CallbackException(e);   
             } finally {
                   try {
                  session.close();
               } catch(HibernateException ex) {
                  throw new CallbackException(ex);            
               }   
             }
         }
        
       }
       histories.clear();
      
   }



Could someone please point out why i'm still getting this exception?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 20, 2005 11:43 pm 
Regular
Regular

Joined: Tue Nov 09, 2004 5:15 pm
Posts: 100
I fixed this problem by changing cascade="none" to cascade="all" for the HistoryEntries set in the Project.hbm.xml. After this i'm getting the following exception when i tried to remove the project in my test case.

Code:

Testcase: testAddAndRemoveProject(com.apple.ermt.dao.ProjectDAOTest):       Caused an ERROR
    [junit] attempted to delete an object of immutable class: [com.apple.ermt.persistence.audit.HistoryEntry]; nested exception is net.sf.hibernate.HibernateException: attempted to delete an object of immutable class: [com.apple.ermt.persistence.audit.HistoryEntry]
    [junit] org.springframework.orm.hibernate.HibernateSystemException: attempted to delete an object of immutable class: [com.apple.ermt.persistence.audit.HistoryEntry]; nested exception is net.sf.hibernate.HibernateException: attempted to delete an object of immutable class: [com.apple.ermt.persistence.audit.HistoryEntry]
    [junit] net.sf.hibernate.HibernateException: attempted to delete an object of immutable class: [com.apple.ermt.persistence.audit.HistoryEntry]
    [junit]     at net.sf.hibernate.impl.SessionImpl.delete(SessionImpl.java:1167)
    [junit]     at net.sf.hibernate.engine.Cascades$1.cascade(Cascades.java:61)
    [junit]     at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:436)
    [junit]     at net.sf.hibernate.engine.Cascades.cascadeCollection(Cascades.java:526)
    [junit]     at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:452)
    [junit]     at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:503)
    [junit]     at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:482)
    [junit]     at net.sf.hibernate.impl.SessionImpl.doDelete(SessionImpl.java:1237)
    [junit]     at net.sf.hibernate.impl.SessionImpl.delete(SessionImpl.java:1172)
    [junit]     at org.springframework.orm.hibernate.HibernateTemplate$17.doInHibernate(HibernateTemplate.java:384)
    [junit]     at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:200)
    [junit]     at org.springframework.orm.hibernate.HibernateTemplate.delete(HibernateTemplate.java:381)
    [junit]     at com.apple.ermt.dao.hibernate.HibernateProjectDAO.removeProject(HibernateProjectDAO.java:59)
    [junit]     at com.apple.ermt.dao.ProjectDAOTest.testAddAndRemoveProject(ProjectDAOTest.java:64)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    [junit]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)



I've marked the HistoryEntry class "immutable" as the history entries should NOT be removed. But as i've set the cascade="all", hibernate is trying to remove the history entry.

Could someone please let me know what should i do to solve this problem?

Thanks in advance!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 21, 2005 7:57 pm 
Regular
Regular

Joined: Tue Nov 09, 2004 5:15 pm
Posts: 100
In my HistoryInterceptor's OnFlushDirty method, the oldValues[] is NULL. As mentioned in this forum, i've set the "select-before-update="true"" in my Project class's mapping file but still i'm having the same problem.

<class
name="com.apple.ermt.model.Project"
table="PROJECT"
dynamic-update="false"
dynamic-insert="false"
select-before-update="true"
>

Do i need to do anything else so that my oldValues[] are NOT NULL?

Thanks in advance!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 21, 2005 9:45 pm 
Newbie

Joined: Sun Feb 13, 2005 10:52 pm
Posts: 3
In my experience select-before-update did not work either. I found I could only get the old values if the object had previously been loaded by the session.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 27, 2005 10:38 am 
Newbie

Joined: Tue May 25, 2004 11:42 am
Posts: 10
Location: Oxford, England
Using Hibernate 2.1.8 I've discovered a way to get the select-before-update to work. I'd like somebody from the Hibernate Team to check out whether this is a good idea or not but it seems ok from my limited testing.

If you have select-before-update turned on then hibernate does actually do a select before updating in order to work out if it needs to update or not. The original values (as selected) as then discarded after use rather than keeping them around so I've added a single line of code to keep them and then they are available in the onFlushDirty() method.

In SessionImpl.flushEntity() method I've added the line in bold around line 2483


Code:
2483            currentPersistentState = persister.getCurrentPersistentState(entry.id, entry.version, this);
2484            if (currentPersistentState!=null) {

Code:
new                    entry.loadedState = currentPersistentState;

Code:
2487               dirtyProperties = persister.findModified(currentPersistentState, values, object, this);
2488               cannotDirtyCheck = false;
2489               cannotDirtyCheck = false;
2490               cannotDirtyCheck = false;
2491               dirtyCheckDoneBySelect = true;
2492            }


I'd like to hear from somebody as to whether it's worth submitting a patch for this.


Top
 Profile  
 
 Post subject: Audit Logging Example
PostPosted: Wed Oct 05, 2005 4:34 pm 
Newbie

Joined: Wed Oct 05, 2005 3:47 pm
Posts: 2
I have been using Hibernate for the last few months and am using the HIA text as a reference. I have been looking at the audit log problem and the example in HIA. I have the example application running. After tracing this discussion I have doubts as whether to use that example as a base for a solution. I have seen this question posted more than once and I still don't see a clear answer. Does it work? Is the main discussion based on comparison of old and new values on update?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 06, 2005 7:29 am 
Newbie

Joined: Tue May 24, 2005 7:08 pm
Posts: 17
Location: Melbourne
There are problems with the approach in the HIA book. Try the approach I posted in the wiki. We are using this successfully in several apps at the moment. http://www.hibernate.org/318.html

This example does not have all supporting code supplied but should be enough to get you going. If you have problems let me know and i'll see if I can help.

cheers,
rob


Top
 Profile  
 
 Post subject: http://www.hibernate.org/318.html
PostPosted: Thu Oct 06, 2005 3:29 pm 
Newbie

Joined: Wed Oct 05, 2005 3:47 pm
Posts: 2
I have taken a look at this previously and specifically at the handling of the session and the comparison of old/new values. I didn't attempt to use any of the ideas because I don't have enough experience with hibernate to have confidence I could figure out the changes (in short order) to the other supporting files, specifically AuditLogRecord and it looks like the AuditLog class was eliminated. If you care to share the supporting files so I can work through the logic changes it would definitely be helpful and appreciated.

Thanks,
Sam


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 06, 2005 7:43 pm 
Newbie

Joined: Tue May 24, 2005 7:08 pm
Posts: 17
Location: Melbourne
Hi Sam,

I'll try to get some time to get something together for you today, otherwise i'll look at it over the weekend. The main reason I haven't posted everything is because we use Spring in our apps and this clouds the detail a little.

In the mean time i'll just dump some of the other classes / interfaces which may help:

Code:

/**
* @author Rob Monie
*
* Interface for Audit Logging of hibernate persistent objects
* Any persistent class that implements this interface will
* be considered 'Auditable' and will have creates, deletes and updates logged
*/

public interface Auditable {
   
}


Code:

/**
* AuditLogRecord model class
*/
public class AuditLogRecord {
   
    // place holder for storing the current entity
     public Auditable entity;
     private Integer id;
     private String message;
     private String entityName;
     private String entityId;
     private String entityAttribute;
     private String oldValue;
     private String newValue;
     private String updatedBy;
     private Date updatedDate;

    /**
     * @return Returns the entity.
     */
    public Auditable getEntity() {
        return entity;
    }

// Constructors

    /** default constructor */
    public AuditLogRecordAbstract() {
    }
   
    /** constructor with id */
    public AuditLogRecordAbstract(Integer id) {
        this.id = id;
    }
   
   
   

    // Property accessors

    /**
     *
     */
    public Integer getId() {
        return this.id;
    }
   
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     *
     */
    public String getMessage() {
        return this.message;
    }
   
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     *
     */
    public String getEntityName() {
        return this.entityName;
    }
   
    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }

    /**
     *
     */
    public String getEntityId() {
        return this.entityId;
    }
   
    public void setEntityId(String entityId) {
        this.entityId = entityId;
    }

    /**
     *
     */
    public String getEntityAttribute() {
        return this.entityAttribute;
    }
   
    public void setEntityAttribute(String entityAttribute) {
        this.entityAttribute = entityAttribute;
    }

    /**
     *
     */
    public String getOldValue() {
        return this.oldValue;
    }
   
    public void setOldValue(String oldValue) {
        this.oldValue = oldValue;
    }

    /**
     *
     */
    public String getNewValue() {
        return this.newValue;
    }
   
    public void setNewValue(String newValue) {
        this.newValue = newValue;
    }

    /**
     *
     */
    public String getUpdatedBy() {
        return this.updatedBy;
    }
   
    public void setUpdatedBy(String updatedBy) {
        this.updatedBy = updatedBy;
    }

    /**
     *
     */
    public Date getUpdatedDate() {
        return this.updatedDate;
    }
   
    public void setUpdatedDate(Date updatedDate) {
        this.updatedDate = updatedDate;
    }


    /**
     * @param entity The entity to set.
     */
    public void setEntity(Auditable entity) {
        this.entity = entity;
    }
   
   
   

}



Code:
/**
*  Interface used to tag classes used as components in Hibernate mappings.  This enables audit logging of component fields to be logged.

* @author Rob Monie
*
*/
public interface Component {
   

}


The relevent parts of my spring config for hibernate and logging. Notice the first session factory has the entityInterceptor registered with it which uses the second session factory to do it's logging.

Code:


<!-- Hibernate SessionFactory -->
   <bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      
      <property name="dataSource">
         <ref bean="dataSource" />
      </property>
      <property name="mappingResources">
         <list>
            <value>au/com/groupware/model/AuditLogRecord.hbm.xml</value>

.... other hibernate mappings go here.....

         </list>
      </property>
      <!-- Define Hibernate and C3P0 connection pooling properties-->
      <property name="hibernateProperties">
         <props>
<!--            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>-->
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.c3p0.minPoolSize">5</prop>
            <prop key="hibernate.c3p0.maxPoolSize">20</prop>
            <prop key="hibernate.timeout">300</prop>
            <prop key="hibernate.max_statement">50</prop>
         </props>
      </property>
      <property name="entityInterceptor"><ref local="auditLogInterceptor"/></property>
   </bean>
   
      <!-- Hibernate SessionFactory Used by Audit Logging Code -->
   <bean id="sessionFactoryAuditLog"
      class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
      <property name="dataSource">
         <ref bean="dataSource" />
      </property>
      <property name="mappingResources">
         <list>
            <value>au/com/groupware/model/AuditLogRecord.hbm.xml</value>

.... other hibernate mappings go here.....

         </list>
      </property>
      <!-- Define Hibernate and C3P0 connection pooling properties-->
      <property name="hibernateProperties">
         <props>
<!--            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>-->
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.c3p0.minPoolSize">5</prop>
            <prop key="hibernate.c3p0.maxPoolSize">20</prop>
            <prop key="hibernate.timeout">300</prop>
            <prop key="hibernate.max_statement">50</prop>
         </props>
      </property>
   </bean>
   
   
    <bean id="auditLogInterceptor" class="au.com.groupware.model.audit.AuditLogInterceptor" singleton="false">
                <property name="sessionFactory"><ref local="sessionFactoryAuditLog"/></property>
     </bean>

[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 23, 2006 9:32 am 
Regular
Regular

Joined: Sat Nov 19, 2005 2:46 pm
Posts: 69
rmonie wrote:
There are problems with the approach in the HIA book. Try the approach I posted in the wiki. We are using this successfully in several apps at the moment. http://www.hibernate.org/318.html

This example does not have all supporting code supplied but should be enough to get you going. If you have problems let me know and i'll see if I can help.

cheers,
rob


Hi Rob,

I hope you don't mind my question so many months after your post (and that you're watching this thread).

I implemented and customized your audit interceptor yesterday as given at http://www.hibernate.org/318.html.

It appears to be working well except for the crucial fact that the audit records saved in the postFlush() method aren't actually saved. In the logs I can see the correct SQL insert statements being generated, and the audit records themselves are correct when I log them.

At 318.html you mention
Quote:
you must use a different sessionFactory for your auditLogging than your usual DAOs. There is good discussion in other places about the reasons for this.

I've not been able to find any clear references or discussion on this topic in the Hibernate forum.
I've found this topic: http://forum.hibernate.org/viewtopic.php?t=932065 where Christian says this:
christian wrote:
The most important thing about an Interceptor to remember is: you can't use the Session. But you can simply create a new temporary Session _on the same JDBC Connection_:

Session newSession = sessionFactory.openSession(oldSession.connection());

newSession....

newSession.flush();
newSession.close();

And I've found this thread:
http://forum.hibernate.org/viewtopic.php?t=955189 where the poster seems to be having the same problem, and there Steve directs suggests searching on the topic "transaction isolation".
I searched and read but found nothing that appears to help.

What is the actual way to get that session.save() in the postFlush() method to actually persist the data?
Or where are there threads which explain this a bit more indepth?

Many thanks,

_________________
Stewart
London, UK


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 45 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.