4

Currently I have an Angular2 app that has an object with nested objects contained in it. The user follows a wizard to update any sections of the object and then clicks save. At the moment, I just send the entire object to the server side to be updated. To do the update, I get the database copy out of the DB and just set all the fields that the client copy has onto the database copy regardless of whether they have changed or not and then save it. This means I also have to loop through all of the nested objects and pull them out of the database and set all of their properties and so on. Everything gets updated, even if it didn't get changed.

This is they way I normally do it, but for this app I need to keep an audit log of objects that were changed. And it would be hard if every time the main object got updated, every other child object logs it was updated as well.

Is there an elegant way to make sure the server side knows only to update the things that have changed (and therefore only triggers the audit log for that object AND doesn't waste time making updates on the DB).

I was thinking about creating an object that stores a list of dirty objects on the client side as the user changes things in the wizard and sending it to the server along with the object so I know which objects NEED to be updated.

Or should I send the entire object to the server like I am doing now, and compare it to the original database object (by looping through all of the objects and comparing them) first to determine what has changed?

It seems like a lot of work. I was wondering if there is a standard way/best practice for doing this.

EDIT 2018-04-24: I just found out about BreezeJS. Is this what I want to be using to achieve my objectives? It keeps track of entities and their modified status and updates them accordingly when required as a change set. Is there anything else similar to this that I should be looking into?

Asagohan
  • 583
  • 5
  • 19

3 Answers3

3

You can use a package deep-diff

var diff = require('deep-diff').diff;

var lhs = {
  name: 'my object',
  description: 'it\'s an object!',
  details: {
    it: 'has',
    an: 'array',
    with: ['a', 'few', 'elements']
  }
};

var rhs = {
  name: 'updated object',
  description: 'it\'s an object!',
  details: {
    it: 'has',
    an: 'array',
    with: ['a', 'few', 'more', 'elements', { than: 'before' }]
  }
};

var differences = diff(lhs, rhs);

And below is the differences object structure

[ { kind: 'E',
    path: [ 'name' ],
    lhs: 'my object',
    rhs: 'updated object' },
  { kind: 'E',
    path: [ 'details', 'with', 2 ],
    lhs: 'elements',
    rhs: 'more' },
  { kind: 'A',
    path: [ 'details', 'with' ],
    index: 3,
    item: { kind: 'N', rhs: 'elements' } },
  { kind: 'A',
    path: [ 'details', 'with' ],
    index: 4,
    item: { kind: 'N', rhs: { than: 'before' } } } ]

Differences

Differences are reported as one or more change records. Change records have the following structure:

kind - indicates the kind of change; will be one of the following:
   N - indicates a newly added property/element
   D - indicates a property/element was deleted
   E - indicates a property/element was edited
   A - indicates a change occurred within an array
path - the property path (from the left-hand-side root)
lhs - the value on the left-hand-side of the comparison (undefined if kind === 'N')
rhs - the value on the right-hand-side of the comparison (undefined if kind === 'D')
index - when kind === 'A', indicates the array index where the change occurred
item - when kind === 'A', contains a nested change record indicating the change that occurred at the array index
Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • This could work. But I was trying to avoid a lot of work. After I get the differences, I still need to look at them and decide what DB statements to run. – Asagohan May 30 '18 at 05:18
0

Ok, how about this..

  1. Instead of handling this at a code level, why don't you send the full object as you are doing now.

  2. In the database, you could setup a trigger on the table(s) in question so that it fires before the update happens. This way you have the data to be updated along with the new data coming from the outside world.

  3. Handle the decision there, about what to audit, what to reject etc. You could even reject the whole update if you see that something is being updated, that shouldn't be allowed.

My 2 cents..

Sharath
  • 969
  • 9
  • 30
0

Use an entity library like Tomato on github.

It is a java library that works like normal entity based persistence mechanisms work, except you don't need any entities other than the single, provided entity. The single, provided Entity class can load and save data from any table or table hierarchy in any schema in any database. In code it looks like this...

Entity e = Entity.createEntityOrView(schema.tablename);
e.setValue("id", 5);
e.load();

or to load sets of records...

e.setFilter("name = 'rodney');
e.load();

The entity class automatically knows when a value becomes dirty, and so marks the entire entity as dirty. It also knows if an entity was loaded from a table or is new (in other words, you always call save(), but it will know whether to perform an INSERT or an UPDATE).

Since all changes are saved via a single method in the Entity class called save(), this method can easily be overridden in a custom Entity class allowing you to modify what happens before and after a save(). In your custom entity class you would be able to output detailed audit data including the table, the primary key and exactly what values changed.

Tomato can be used for immediate database gratification wherever JSON is used, like angular or vue (and any non-java code) via the single provided web service.

Check out the Tomato library on github!

I am the author of the Tomato library on github.

Rodney P. Barbati
  • 1,883
  • 24
  • 18