Return-Path: X-Original-To: apmail-openjpa-users-archive@minotaur.apache.org Delivered-To: apmail-openjpa-users-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1524D434B for ; Thu, 7 Jul 2011 20:33:40 +0000 (UTC) Received: (qmail 18706 invoked by uid 500); 7 Jul 2011 20:33:39 -0000 Delivered-To: apmail-openjpa-users-archive@openjpa.apache.org Received: (qmail 18676 invoked by uid 500); 7 Jul 2011 20:33:39 -0000 Mailing-List: contact users-help@openjpa.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: users@openjpa.apache.org Delivered-To: mailing list users@openjpa.apache.org Received: (qmail 18668 invoked by uid 99); 7 Jul 2011 20:33:39 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 07 Jul 2011 20:33:39 +0000 X-ASF-Spam-Status: No, hits=2.8 required=5.0 tests=FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_DNSWL_LOW,SPF_PASS,T_TO_NO_BRKTS_FREEMAIL,URI_HEX X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of bengt.rodehav@gmail.com designates 209.85.161.41 as permitted sender) Received: from [209.85.161.41] (HELO mail-fx0-f41.google.com) (209.85.161.41) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 07 Jul 2011 20:33:34 +0000 Received: by fxg9 with SMTP id 9so1637605fxg.0 for ; Thu, 07 Jul 2011 13:33:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type; bh=ooUc5g7Cm+0yV5Pjy1yd1gon+6Mto3PehNZRVS/NK8g=; b=uTWHRV4KN8+ZlwjsdTdVClHsurtRwQdGhwbj6zgz+aHPV3TxqfS67PlbT3F9eDvfzX TEK16eIYkhu+VTI8gb2wMIQeNLlvhSuQdypePguDwkj53rS8Ej9gsGy2iPg4jUGtReBd vG3BkQmAIgBWmBxby0P3zNjdqwC2KjXgLoD88= MIME-Version: 1.0 Received: by 10.223.75.139 with SMTP id y11mr1859045faj.133.1310070793282; Thu, 07 Jul 2011 13:33:13 -0700 (PDT) Sender: bengt.rodehav@gmail.com Received: by 10.223.78.205 with HTTP; Thu, 7 Jul 2011 13:33:13 -0700 (PDT) In-Reply-To: References: <201107071535.45495.david.goodenough@btconnect.com> <1310051747.2026.6.camel@at2582-laptop> Date: Thu, 7 Jul 2011 22:33:13 +0200 X-Google-Sender-Auth: Uv_T6bh-927OspYFP09Z5EHQZqE Message-ID: Subject: Re: Audit log with OpenJPA From: Bengt Rodehav To: users@openjpa.apache.org Content-Type: multipart/alternative; boundary=0015174c406643a48b04a780a04b --0015174c406643a48b04a780a04b Content-Type: text/plain; charset=ISO-8859-1 Wow - lots of discussion here. I must have hit a good topic for once... I don't see why you shouldn't be proud of your solution. Storing all versions is a well known idiom for preserving your history. Basically you don't allow updates but create new versions all the time instead. I have considered it but I'm a bit afraid for the performance impact since performance is critical. I've never done this with JPA though. I guess from your mail that it's not that straight forward. Ideally what you would like is of course to have a composit key consisting of the id and version together. On every update a new instance would be persisted with the same id but a higher version. I don't think the existing version should be updated at all. I would prefer just creating a new version and leaving the previous (all the previous versions) intact. Doesn't JPA allow you to do this? /Bengt 2011/7/7 No1UNo > Bengt: > > I'm enjoying this discussion because of the gymnastics that were required > for my solutions. There is no easy way that I am aware of -- but I would > LOVE to be wrong. > > Here's what I did (and, no, I'm not particularly proud of the solution): > > (1) For the primary entities, add tracking data (timestamp, user, etc.) > plus an entityID. > (2) On an update, > * clone the data in the entity and update the tracking data. Copy > the old entityID. > * mark the previous entity as out-of-date (to speed up searches) > * persist both entities > (3) On an insert, > * persist the new entity and increment the entityID > (4) Update the queries to extract only those records where the > 'out-of-date' flag was not set. > > This results in both current and historical entities being preserved in the > same table. This will reduce performance as the indices are larger than are > necessary for daily operation. This solution can be combined with a nightly > script which moves out-of-date records from the main table to archived > tables. > > The entity copy is a real pain but seems to be necessary. See the 'How to > persist duplicate of an entity?' thread from January 2011. As I wrote > earlier: > > > I would _love_ to have function that would 'reset' a detached entity. > Perhaps something like > > > > em.detach(myObj); // ensure that the entity has been detached. > > OpenJPAEntityManager kem = OpenJPAPersistence.cast(em); > > kem.reset(myObj); > > > > with the result of the 'reset' operation being a class which is again > virgin, i.e. > > > > myObj.id == 0 > > myObj.version = 0 > > myObj.pcDetachedState == null > > myObj.pcStateManager == null > > > > and so forth for any children. > > > This would greatly simplify the cloning process. > > -=- Jerry > > > > > > On Jul 7, 2011, at 12:50 PM, Bengt Rodehav [via OpenJPA] wrote: > > > I actually use the same approach as Hades for createdBy, updatedBy, > > createdWhen and updatedWhen. In addition to this basic audit logging I > also > > want to log all historical versions together with information about who > > updated the object. > > > > I've read a little bit about Envers. I didn't want to bring it up since > this > > is an OpenJPA mailing list. It does look interesting but I think it > requires > > Hibernate which I do not intend to go back to. (I'm actually moving away > > from Hibernate). Also, I'm a bit hesitant to store "copies" of my rows in > > special audit tables since it also means database migration of those > tables. > > I think serializing the audit log entries and putting them in one column > is > > a better approach from a maintenance perspective. > > > > But it would be nice if OpenJPA would provide a callback or some > mechanism > > (even if it's not standard JPA) that would allow further updates/inserts > in > > a callback. > > > > Are there any such plans? > > > > /Bengt > > > > 2011/7/7 Andrew Thompson <[hidden email]> > > > > > You might take a look at how hades > > > ( > > > > http://hades.synyx.org/static/2.x/site/org.synyx.hades/reference/html/auditing.html > ) > > > does something close to what you're describing. Or > > > http://www.jboss.org/envers > > > > > > -Andy > > > > > > On Thu, 2011-07-07 at 15:35 +0100, David Goodenough wrote: > > > > On Thursday 07 Jul 2011, Bengt Rodehav wrote: > > > > > I'm using OpenJPA for persistence and would like to audit log any > > > changes > > > > > made to my entities. I serialize the objects to JSON (with Gson) > and > > > store > > > > > them in a separate table in the database. Since the audit log needs > to > > > have > > > > > the correct id's, the audit logging must take place after the > entity > > > has > > > > > been persisted. > > > > > > > > > > I was hoping I could use the @PostPersist and @PostUpdate life > cycle > > > > > callbacks for this. I do seem to have the right information > available > > > and > > > > > the serialization works fine but I don't know how I can persist my > > > audit > > > > > log entries at this point. From what I've read, I'm not allowed to > use > > > the > > > > > entity manager in a "Post" lifecycle callback which of course makes > > > this > > > > > hard. > > > > > > > > > > What do you recommend? Is there a good place in JPA/OpenJPA where I > > > > > automatically can trigger the storing of an audit log entry as > > > described > > > > > above. Of course I can move this logic up from the persistence > layer to > > > a > > > > > place where I can first have the entity manager persist my entity > and > > > then > > > > > explicitly call another service to do the audit log. However, this > is a > > > > > pretty general mechanism that I would like to have automatic > support > > > for in > > > > > my framework which is why I would like to have it pushed down into > the > > > > > persistence layer. > > > > > > > > > > Any ideas? > > > > > > > > > > /Bengt > > > > You could of course cheat. > > > > > > > > While you can not access the entiry manager, there is nothing to stop > you > > > > using JDBC. It would probably not be a good idea to access a table > that > > > > JPA is using, but if this audit trail is write only for this app and > only > > > > read elsewhere that would solve the problem. > > > > > > > > David > > > > > > > > > > > > If you reply to this email, your message will be added to the discussion > below: > > > http://openjpa.208410.n2.nabble.com/Audit-log-with-OpenJPA-tp6557932p6559076.html > > To start a new topic under OpenJPA Users, email > ml-node+208411-1703014788-244680@n2.nabble.com > > To unsubscribe from OpenJPA Users, click here. > > > > -- > View this message in context: > http://openjpa.208410.n2.nabble.com/Audit-log-with-OpenJPA-tp6557932p6559172.html > Sent from the OpenJPA Users mailing list archive at Nabble.com. --0015174c406643a48b04a780a04b--