Cayenne stores the original values, but they are in DbEntity representation rather than ObjEntity representation which makes comparing the two difficult. Without writing a lot of code to convert and compare your best bet would be to use a more efficient data structure without any extra unneeded space. That would be an array (Object[]) that is smart enough to map a fixed set of string keys into array indexes. To do this you'll need a HashMap<String, Integer> per ObjEntity(table) that maps from string key to array index. Then all of your CayenneDataObjects will need an Object[] with the original values.
On Tue, Sep 11, 2018 at 10:58 AM Matt R Watson <m...@swarmbox.com> wrote: > Thanks mrg. > > I am aware that Cayenne knows about the original values, but trying to > find an efficient way to access them. Or at least more efficient than the > Map we are currently using, which is heavy on memory yet quick on access > time (and easy to read code). I’ve seen your utilities in the past when > searching for a solution for this, but I don’t see anything thats > comparable to finding the original value of a specific property on a > specific object. I also don’t see where you are grabbing the original value > of a relationship. I know the snapshot can show me the original DataRow > values, but I don’t think those are always the same “type” as the actual > DataObject properties. > > Still hoping for solution for our current code (that doesn’t have to loop > over all modified objects, every time): > > inventoryAdjustment.isPropertyModified(“date”) > inventoryAdjustment.getOriginalProperty(“date”) > > with something like: > > Cayenne.isPropertyModified(inventoryAdjustment, "date”) > Cayenne.getOriginalProperty(inventoryAdjustment, "date”) > > Thanks, > Matt > > > On Sep 11, 2018, at 5:31 AM, Michael Gentry <blackn...@gmail.com> wrote: > > > > Hi Matt, > > > > Cayenne already keeps track of the original values for you. This is > needed > > in order to do optimistic locking, plus it allows Cayenne to only send > over > > changes in a record instead of the entire record when you are doing an > > UPDATE. > > > > I haven't tried this approach on the field-based version of Cayenne yet, > > but these two utility methods are similar and illustrate how to find the > > underlying values and detect the changes, at least in 3.x: > > > > > https://gist.github.com/mrg/4dce22b67175c27f4047#file-cayenneutils-java-L124 > > > > > https://gist.github.com/mrg/4dce22b67175c27f4047#file-cayenneutils-java-L184 > > > > I believe you could adapt for your purposes/needs pretty readily. > > > > mrg > > > > > > On Mon, Sep 10, 2018 at 8:04 PM Matt R Watson <m...@swarmbox.com> wrote: > > > >> Now that the DataObject classes are “field based”, I would like to find > a > >> way to replace the heavy Map we have placed on all of our DataObject > >> classes. > >> > >> We extend Cayenne’s default class and added a HashMap to keep track of > the > >> original values (as it changes) since the object has been loaded and > before > >> committing. (see our class below) > >> > >> This allows us to check if something is modified ( > >> inventoryAdjustment.isPropertyModified(“date”), or > >> inventoryAdjustment.getOriginalProperty(“date”) ) > >> > >> I’d like to find a Cayenne friendly way of doing this. Any suggestions? > >> > >> Thanks, > >> Matt > >> > >> ---------------------------------------------------- > >> > >> > >> public class CayenneBaseDataObject extends CayenneDataObject { > >> > >> /** > >> * Stores the original values for this object's properties. Uses > >> the > >> * property name string as the key for each entry. Its purpose is > >> to keep > >> * track of any original values since the object was initialized > >> or last > >> * committed. > >> */ > >> private final Map<String,Object> originalPropertyMap = New.map(); > >> > >> /** > >> * Initializes the originalPropertyMap. Used as a callback during > >> the > >> */ > >> public void initializeOriginalPropertyMap() { > >> originalPropertyMap.clear(); > >> } > >> > >> @Override > >> protected void beforePropertyWrite(String propName, Object oldValue, > >> Object newValue) { > >> if (!originalPropertyMap.containsKey(propName)) { > >> originalPropertyMap.put(propName, oldValue); > >> } > >> > >> super.beforePropertyWrite(propName, oldValue, newValue); > >> } > >> > >> /** > >> * Overrides > >> * {@link org.apache.cayenne.DataObject#writeProperty(String, > >> Object)} by > >> * saving a {@link CayenneBaseDataObject}'s existing property > >> value, if any, > >> * to the {@link #originalPropertyMap} prior to updating the > >> * {@link CayenneBaseDataObject}'s property with a new value. > >> * > >> * @param relationship > >> * the name of the to-one-relationship > >> * @param value > >> * the value used to set the to-one-relationship > >> * @param reverse > >> * a boolean indicating whether to set the reverse > >> relationship as well > >> */ > >> @Override > >> public void setToOneTarget(final String relationship, final > >> org.apache.cayenne.DataObject value, final boolean reverse) { > >> if (!originalPropertyMap.containsKey(relationship)) { > >> originalPropertyMap.put(relationship, > >> this.readProperty(relationship)); > >> } > >> > >> super.setToOneTarget(relationship, value, reverse); > >> } > >> > >> > >> @Override > >> public Object getOriginalProperty(final String property) { > >> if (!originalPropertyMap.containsKey(property)) { > >> return this.readProperty(property); > >> } > >> > >> return originalPropertyMap.get(property); > >> } > >> > >> @Override > >> public Boolean isPropertyModified(final String property) { > >> final Object original = > this.getOriginalProperty(property); > >> final Object current = this.readProperty(property); > >> > >> return !Objects.equals(original, current); > >> } > >> > >> } > >> > >> > >