Return-Path: Delivered-To: apmail-cayenne-user-archive@www.apache.org Received: (qmail 71361 invoked from network); 1 Nov 2010 21:54:41 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 1 Nov 2010 21:54:41 -0000 Received: (qmail 16022 invoked by uid 500); 1 Nov 2010 21:55:12 -0000 Delivered-To: apmail-cayenne-user-archive@cayenne.apache.org Received: (qmail 15970 invoked by uid 500); 1 Nov 2010 21:55:11 -0000 Mailing-List: contact user-help@cayenne.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: user@cayenne.apache.org Delivered-To: mailing list user@cayenne.apache.org Received: (qmail 15962 invoked by uid 99); 1 Nov 2010 21:55:11 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Nov 2010 21:55:11 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of brunorene@holos.pt designates 193.126.127.18 as permitted sender) Received: from [193.126.127.18] (HELO vm-mail.dmz.holos.pt) (193.126.127.18) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 01 Nov 2010 21:55:03 +0000 Received: (qmail 14729 invoked from network); 1 Nov 2010 21:54:37 -0000 Received: from unknown (HELO pcportbrd) (brd@[95.93.134.16]) (envelope-sender ) by vm-mail.dmz.holos.pt (qmail-ldap-1.03) with AES128-SHA encrypted SMTP for ; 1 Nov 2010 21:54:37 -0000 From: =?iso-8859-1?Q?Bruno_Ren=E9_Santos?= To: References: <002401cb76a3$4b60e820$e222b860$@pt> <4CCA6229.4050807@maniatis.org> <001b01cb7780$17dfc010$479f4030$@pt> <001901cb7841$b5ddf220$2199d660$@pt> In-Reply-To: Subject: RE: Modified Fields Date: Mon, 1 Nov 2010 21:53:34 -0000 Message-ID: <000c01cb7a0f$5eeefd90$1cccf8b0$@pt> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable X-Mailer: Microsoft Office Outlook 12.0 Thread-Index: Act5zbCzotk4ZJ/VQrC+oj3WlzVfDwAQXERA Content-Language: pt Thanx a lot. I will look into this code. Regards Bruno Santos -----Mensagem original----- De: jbryanlewis@gmail.com [mailto:jbryanlewis@gmail.com] Em nome de = Bryan Lewis Enviada: segunda-feira, 1 de Novembro de 2010 14:03 Para: user@cayenne.apache.org Assunto: Re: Modified Fields I've written code that logs changes to the database. I'm appending it = below with some disclaimers. It's stable -- we've been using it in production = for several years now -- but it might be more complicated than you need. = I've boiled it down somewhat here... removed the frill of ignoring a set of specified entity and attribute names. Maybe the only parts you'll care about are in the first quarter, where it collects all the changed = objects and looks at each one's snapshot. When you see ModelObject, think CayenneDataObject; ModelObject is my = "wedge" super-class. /** * For each object in the list of modified, new or deleted objects, * write a ChangeHistory record if there was a real change in an attribute * or a to-one relationship. Called immediately before dc.commitChanges(). */ @SuppressWarnings("unchecked") private static void processRealChanges(DataContext dc) { // Collect all the changed objects together. Collection objects =3D (Collection) dc.newObjects(); objects.addAll((List) dc.modifiedObjects()); objects.addAll((List) dc.deletedObjects()); for (ModelObject object : objects) { // Get the class name without the "model." prefix. ObjEntity entity =3D object.getObjEntity(); String entityName =3D object.getEntityName(); // If it's new, write a single history record with // object.toStringCompact() as the change description. if (object.isNew()) { String change =3D object.toStringCompact(); writeHistory(dc, object, change, RDChangeType.changeTypeInsert(dc)); continue; } // If it's deleted, write a single history record. if (object.isDeleted()) { String change =3D object.toStringCompact(); writeHistory(dc, object, change, RDChangeType.changeTypeDelete(dc)); continue; } // The rest is for modified objects. Map snapshot =3D dc.getObjectStore().getSnapshot(object.getObjectId()); List changes =3D null; changes =3D CollFactory.newList(); // First the attributes. Collection attributes =3D = entity.getAttributes(); for (ObjAttribute attribute : attributes) { String name =3D attribute.getName(); Object newValue =3D object.readProperty(name); // The snapshot uses database attribute names. String dbName =3D attribute.getDbAttributePath(); Object oldValue =3D snapshot.get(dbName); if (valueChanged(oldValue, newValue)) { String desc =3D null; desc =3D entityName + "." + name; log.debug("# Real change in attribute " + desc); changes.add(changeDescription(name, oldValue, newValue)); } } // Then the to-one relationships. String pkName =3D null; DbEntity dbEntity =3D entity.getDbEntity(); Collection pks =3D dbEntity.getPrimaryKeys(); if (pks.size() =3D=3D 1) { DbAttribute pk =3D pks.iterator().next(); pkName =3D pk.getName(); } for (ObjRelationship relationship : = entity.getRelationships()) { if (relationship.isToMany()) { continue; } // Guided by code from cayenne's access.DataRowUtils... determine // whether there was a change by looking at the target objectId. String name =3D relationship.getName(); Object targetObject =3D = object.readPropertyDirectly(name); // If it's a fault it wasn't modified. if (targetObject instanceof Fault) { continue; } ModelObject toOneTarget =3D (ModelObject) targetObject; // Compare the db values. DbRelationship dbRelationship =3D relationship.getDbRelationships().get(0); DbAttribute dbAttribute =3D dbRelationship.getSourceAttributes().iterator().next(); String sourceAttributeName =3D dbAttribute.getName(); Object oldValue =3D snapshot.get(sourceAttributeName); dbAttribute =3D dbRelationship.getTargetAttributes().iterator().next(); String targetAttributeName =3D dbAttribute.getName(); Object newValue =3D null; if (toOneTarget !=3D null && (toOneTarget.isPersistent() = || toOneTarget.isHollow())) { newValue =3D toOneTarget.getSnapshotDbProperty(targetAttributeName); } // Be careful if the newValue is null and the = relationship is based on // the source object's PK which can't be null. For = example, Company.rating // is based on the company's PK but not all companies = have a rating. boolean ignoreNewNullValue =3D (newValue =3D=3D null && sourceAttributeName.equals(pkName)); if (!ignoreNewNullValue && valueChanged(oldValue, = newValue)) { changes.add(changeDescription(name, oldValue, newValue)); } } if (changes.size() > 0) { Collections.sort(changes); String changeDescription =3D CString.componentsJoinedByString(changes, "\n"); writeHistory(dc, object, changeDescription, RDChangeType.changeTypeUpdate(dc)); } } } On Mon, Nov 1, 2010 at 9:27 AM, Mike Kienenberger = wrote: > It's been a while, so I don't remember if it is still relevant for = 3.x, but > > https://issues.apache.org/jira/browse/CAY-414 > > contains code for audit logging under Cayenne 2.0. > > > On Sat, Oct 30, 2010 at 10:49 AM, Bruno Ren=E9 Santos = > wrote: > > I only found the hasChanges()... there is, on the other hand, a > > getSnapshot(ObjectId) function. Could I use it to compare to my > > CayenneDataObject, field by field, in order to check which ones were > changed? > > This is because I need to create log entries where for each update I = only > > specify the key-value pair for the modified fields. > > > > Thanx > > Bruno > > > > -----Mensagem original----- > > De: Michael Gentry [mailto:mgentry@masslight.net] > > Enviada: sexta-feira, 29 de Outubro de 2010 16:59 > > Para: user@cayenne.apache.org > > Assunto: Re: Modified Fields > > > > Hi Bruno, > > > > Try dataContext.getObjectStore().getChanges(). > > > > mrg > > > > > > On Fri, Oct 29, 2010 at 11:43 AM, Bruno Ren=E9 Santos = > wrote: > >> Hello all, > >> > >> Anyone knows how can I know which fields on a CayenneDataObject = were > modified > >> since the last read? > >> > >> Thanx > >> Bruno Santos > >> > >> > > > > >