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