Thanks for the detailed description!

First of all I might have been easy to misunderstand, but I don't want
to try to implement auditing in general. My knowledge is not enough for
that right now.

I have a project that implements auditing so, that I have a
SITE_QUESTION_ASSOCIATION table/entity that is a superclass of ANSWER
and PROVISION. 

Each site must answer questions; in case of a negative answer sites can
provide provisions to handle the situation. Questions can have default
answers (where siteId = null).

base class is:

<hibernate-mapping>
        <class 
        
name="com.netvisor.risk_management.persistence.SiteQuestionAssociation"
                table="site_question"
                discriminator-value="b"
        >
                <cache usage="nonstrict-read-write"/>

                <id column="id" name="id">
                        <generator class="native"/>
                </id>

                <discriminator column="subclass" type="character"/>
                        
                <property name="auditInfo"
type="com.netvisor.risk_management.persistence.AuditInfoType"
not-null="true">
                        <column name="created" not-null="true"/>
                        <column name="createdBy" not-null="true"/>
                </property>

                <many-to-one
                        name="site"
                        column="SiteId"
                        cascade="none"
                        not-null="false"
                />      <!-- not-null="false" is there because default
values are stored with null -->

                <many-to-one
                        name="question"
                        column="QuestionId"
                        cascade="none"
                        not-null="true"
                />
                        
        </class>
</hibernate-mapping>

when the database is changed, I always save a new copy of these
entities, and when creating a report at time t I always select the
(max(anditInfo.created) where anditInfo.created <= t) row.

this way I can (re)create a report at any time in the past.

currently I achive it by hand:

public void HibernateEntityMetadata.save(Session session, Object entity)
throws MetadataException
{
        try
        {
                if (entity instanceof Auditable)
                {
                        session.evict(entity);
                        session.save(entity);
                }
                else
                {
                        session.saveOrUpdate(entity);
                }
        }
        catch (HibernateException e)
        {
                throw new MetadataException("Failed to save entity", e);
        }
}

but it does not work if an Auditable is saved due to some cascading...

so what would help me in this situation: being able to augment Session
from the Interceptor in onFlushDirty to save a new row. I've tried to
reassign the id of the entity, result is an exception (couldn't trick
Hibernate :)

I was told to use a database trigger. I would like to avoid that.

:: What are you are trying to do requires dealing (at the very 
:: least) with these issues:
:: 
:: - What are you going to do with primary keys?
:: 
:: The simplest thing is to generate a new id. But then the 
:: auditing mechanism must have a way of associating the new id 
:: with the old id. Presumably that table would look something 
:: like (object_id, old_version_id, change_date) with the 
:: primary key of (object_id, old_version_id). Of course, keys 
:: of more than one column make it more complicated.

as you can see in my situation, associating old id's is not important
for me.

:: - What are you going to do with unique constraints?
:: 
:: The primary key case is just a special case of a unique 
:: constraint. Any other unique constraints in your model needs 
:: to be handled. The interceptor can simply uniquify values, 
:: e.g. by appending a timestamp. Or you can not have unique 
:: constraints. Another option is to use a separate table for 
:: all old values. That table can omit the unique constraints 
:: and have a primary key along the lines described above, 
:: (object_id, old_version_id).

that's why I have trouble with the trigger. I don't want to enumerate
all columns at ?????? (I'm looking for a nice solution, not a working
one)

CREATE OR REPLACE TRIGGER AUDITING 
BEFORE UPDATE 
ON SITE_QUESTION 
REFERENCING NEW AS NEW OLD AS OLD 
FOR EACH ROW 
Declare 

rs SITE_QUESTION%rowtype; 

Begin 

select * into rs from SITE_QUESTION where id = :old.id; 

select HIBERNATE_SEQUENCE.nextval into rs.id from dual; 

insert into SITE_QUESTION ??????; 

End;

:: - What are you going to do with one-to-many or many-to-many 
:: associations?
:: 
:: Auditing *-to-many associations is not as simple as 
:: recording an old value, because there are many values. You 
:: could record the whole collection of values as of each 
:: change to the association, or you could record just what 
:: changes are made.
:: 
:: - What are you going to do with inverse associations?
:: 
:: If old data is in the same table as new data, foreign key 
:: references to the audited table need to be handled in a 
:: manner that does not leave them pointing at old data.
:: 
:: - What about deletion of associated objects?
:: 
:: Old data that has foreign keys needs to deal with deletion 
:: of the referenced object. This could be as simple as not 
:: using foreign keys in the auditing data, or declaring those 
:: keys as "on delete cascade"  or "on delete set null".

The lack of my answers is why I don't try to implement auditing in
general... :)

:: It may be that none of these problems affect your use case. 
:: If so, it would help to understand what you are trying to do 
:: in a little more 
:: detail.

hope I was clear.

:: However, I imagine that these problems make it difficult to submit a 
:: patch
:: that adds support for the Auditable interface as proposed.
:: 
::   -- Archit Shah ([EMAIL PROTECTED])
:: 
:: On Thursday, Apr 22, 2004, at 13:59 US/Eastern, Lendvai Attila wrote:
:: 
:: > in short: can i achive from an interceptor that entities that 
:: > implement Auditable and are (directly/indirectly) passed to 
:: > saveOrUpdate() will automatically be saved into a new row?
:: >
:: > any hints how to implement in Hibernate for a patch candidate?

I only meant a patch that lets me implement saving a new row when
updating an Auditable.

thanks,

- 101



-------------------------------------------------------
This SF.net email is sponsored by: The Robotic Monkeys at ThinkGeek
For a limited time only, get FREE Ground shipping on all orders of $35
or more. Hurry up and shop folks, this offer expires April 30th!
http://www.thinkgeek.com/freeshipping/?cpg297
_______________________________________________
hibernate-devel mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/hibernate-devel

Reply via email to