Hey Jeff, it's generally better to post questions to the mailing list
as others may have better ideas than my own, so I'm replying to this
on the mailing list as well.
1) Yes
2) Yes
3) Yes, I collect schema, table, column, and new value for the
inserted record (You can delete the code that handles the update and
delete cases). . I also want a relationship from my audit record to
the record being audited. So I retrieve the primary key(s) for the
record and store that as well. This is what
setForeignKeyRepresentation does. If it's a single INTEGER primary
key, then I store it as FOREIGN_KEY. Otherwise, I store string
representation of the keys as FKEY_CONDITION.
So I build up a list of audit log information (in map form) to be
subsequently written out later. ProcessAuditRecordMapList() is what
writes out the records. I create an InsertQuery, and because all
audit records look the same, I simply bind every set of audit
information to the InsertQuery and then manually execute it. Most of
the code in processAuditRecordMapList simply deals with manually
generating a unique primary key for each audit record. Because my
database fields match the Map fields, I can directly assign the audit
records to the insert query without any translation of the map keys
and database table field names.
You can use insertBatchQuery.getObjectId().getEntityName() to get the
name of the ObjEntity and use that to filter out all by Alert objects
if you don't want to use the table name.
To iterate through the database table field values, you would use the
same code that's already there:
=====
List dbAttributes =
insertBatchQuery.getDbAttributes();
while(insertBatchQuery.next()) {
for(int i = 0; i < dbAttributes.size();
i++) {
Map auditRecordMap = new
HashMap();
DbAttribute dbAttribute =
(DbAttribute) dbAttributes.get(i);
Object value =
insertBatchQuery.getValue(i);
=====
dbAttribute.getName() is the field name, and value is the value.
Don't know the answer to your validateForSave() question as I haven't
used it. However, this finishedRunQueries() hook is the only place
available where your insert statements have been committed to the
database (and thus have primary keys assigned) and yet is before the
transaction has been committed so you can get your audit logging in on
the same transaction.
The easiest way I've found to understand how all of this stuff works
together and what's available
(ObjEntity/ObjAttribute/DbEntity/DbAttribute) is to set a breakpoint
and look at the values in the debugger. It's the same stuff you see
in the modeler, but for myself, it didn't all come together until I
saw it with my actual data in the debugger.
On 9/30/06, Jeff de Vries <[EMAIL PROTECTED]> wrote:
Hi, sorry to bother you again. I have a few questions on how to use the
audit logging stuff ...
1) To use your AuditLoggingDataContextFactory to create data contexts
(we're using thread-bound data-contexts in a web app), we set the
"DataContext Factory" property using CayenneModeler for our domain,
correct? This will cause the data-contexts that are created and bound
to our webapp threads to be wrapped by the AuditLoggingDataContextDelegate?
2) Your patch adds the method finishedRunQueries(DataContext
dataContext, List queryList) to DataContextDelegate, correct?
3) I'm still trying to figure out the example finishedRunQueries() in
AuditLoggingDataContextFactory ... (sorry, I'm not a Cayenne expert!).
It looks like queryList is a list of queries, where a query can be an
insert, update, or delete. For an insert (the only case I'm interested
in), it looks like you get a set of Schema/Table/Column/Value tuples?
And then do some stuff with primary keys or something? To be honest,
I'm pretty lost at this point with InsertQueries, dbAttributes, and
pkAttributes, etc! I think you're building up a list of audit log
objects (in map form) to be subsequently written out later? And I have
no idea what processAuditRecordMapList() is doing ...
All I need is: If we're going to Insert an object into the db, check to
see if the object is an Alert (one of our classes), and if it is, pull
some fields out of it, and conditionally (i.e. not every Alert gets an
audit record, depending on the value of the fields) create a new object
with those fields and write that object to the database as well. I
think I can check the class of the object (indirectly) by looking at
dbEntity.getName() and seeing if it is "alert" (i.e. the table name),
but I don't see how to pick out the values of the other fields from the
object.
If I'm asking too many questions, or the time required to answer the
questions is too much, just say so!
Could I get the same affect by just overloading validateForSave() on the
Alert objects?
What I'm *really* trying to do is that we have about 15-20 different
types of alerts, and a bunch of rules that specify some additional
processing that needs to take place when certain types of alerts are
generated. Rather than scatter the rules around the umpteen different
places alerts are created, I thought I'd be "clever" and put all the
rule processing stuff in one place, looking at the alerts as they get
written out. So, as a complete workaround, I could just go add the
rules to the umpteen different places the alerts are getting generated.
Or, if there was a convenient place to hook some "aspect-oriented"
programming stuff (which is what I guess I'm doing), like a
Alert.onSave(), that would work too.
Anyway, any help or suggestions would be greatly appreciated!
Thanks again,
Jeff
Mike Kienenberger wrote:
> Yes, I'll be adding it to 2.0/3.0 "soon" where soon will depend on
> what time I have available over the next month. But we are committed
> to getting audit support into Cayenne. The only discussion left is
> whether this will be a DataContextDelegate method or an Event, but
> switching between the two should be a trivial change.
>
> Another option is I can send you my own patched Cayenne 1.2 jars, but
> you'll have to take outer join support along with it :-)
>
>
> On 9/15/06, Jeff de Vries <[EMAIL PROTECTED]> wrote:
>> This looks good, but I'm a little nervous about patching Cayenne. Will
>> this patch make it into 1.3 (or 2.0 or whatever is next), or will I be
>> stuck using 1.2 if I use this? Also, to apply the patch I assume I need
>> to check Cayenne 1.2 from svn or cvs and then apply the patch?
>>
>> Thanks again!!
>> Jeff
>>
>> Mike Kienenberger wrote:
>> > Jeff,
>> >
>> > In my opinion, this will not do what you want.
>> >
>> > Please see this jira issue for an example of how to solve this problem
>> > (currently, it requires a patch to Cayenne 1.2).
>> >
>> > http://issues.apache.org/cayenne/browse/CAY-414
>> >
>> > On 9/14/06, Jeff de Vries <[EMAIL PROTECTED]> wrote:
>> >> I want to add a record to an audit table whenever certain objects are
>> >> saved to the database. Based on earlier posts, I think I need to
>> create
>> >> a custom TransactionDelegate, and override didCommit() (or
>> >> willCommit()). What I don't understand is how to access the objects
>> >> that are going to be saved for this transaction so I can pull
>> relevant
>> >> information out for the audit record. Are there any examples of
>> >> doing this?
>> >>
>> >> Thanks,
>> >> Jeff de Vries
>> >>
>> >>
>>