Skip to content

Partially updateable entities

Stephan Bösebeck edited this page Aug 23, 2013 · 1 revision

Partially Updatable Entities

The idea behind partial updates is, that only the changes to an entity are transmitted to the database and will thus reduce the load on network and Mongodb itself. Partially updatable entities is the implementation in Morphium and can be used in several ways.

Application driven

This is the easiest way - you already know, what fields you changed and maybe you even do not want to store fields, that you actually did change. In that case, call the updateUsingFields-Method:

   UncachedObject o....
   o.setValue("A value");
   o.setCounter(105);
   Morphium.get().updateUsingFields(o,"value"); //does only send updates for Value to mongodb
                                                                         //counter is ignored

updateUsingFields honors the lifecycle methods as well as caches (write cache or clear read_cache on write). take a look at some code from the corresponding junit-test for better understanding:

 UncachedObject o... //read from MongoDB
            o.setValue("Updated!");
            Morphium.get().updateUsingFields(o, "value");
            log.info("uncached object altered... look for it");
            Query<UncachedObject> c=Morphium.get().createQueryFor(UncachedObject.class);
            UncachedObject fnd= (UncachedObject) c.f("_id").eq( o.getMongoId()).get();
            assert(fnd.getValue().equals("Updated!")):"Value not changed? "+fnd.getValue();

Application driven - 2nd way

Implement the interface PartiallyUpdateablewhich ensures, that one method is implemented in your entity, returning all fields that should be persisted with the next save operation.

@Entity
public class SimpleEntitiy  implements ParitallyUpdateable {
      private String v1;
      @Property(fieldName="name")
      private String theName;

     ....
      private List<String> updateFields=new ArrayList<String>();
      ....

      public void setV1(String v) {
            v1=v;
            updateFields.add("v1");
     }

     public void setTheName(String n) {
          theName=n;
          updateFields.add("name");
     }
    List<String> getAlteredFields() {
         return updateFields;
    }

This should illustrate, how this works. When store with such an entity-object is called, morphium checks whether or not PartiallyUpdateable is implemented and calls getAlteredFields to do a partial update (by calling updateUsingFields)

Through proxy

Morphium is able to create a transparent proxy for your entities, taking care of all this mentioned above. See here the code from the JUnit-Test:

        UncachedObject uo=new UncachedObject();
        uo=Morphium.get().createPartiallyUpdateableEntity(uo);
        assert(uo instanceof PartiallyUpdateable):"Created proxy incorrect";
        uo.setValue("A TEST");
        List<String> alteredFields = ((PartiallyUpdateable) uo).getAlteredFields();
        for (String f:alteredFields) {
            log.info("Field altered: "+f);
        }
        assert(alteredFields.contains("value")):"Field not set?";

The Object created by createPartiallyUpdateableEntity is a proxy object which does intercept all set-Method calls. BUT: to be sure, that the correct field is stored in your List of altered fields, the method should have a UpdatingField annotation attached, to specify the field, that this setter does alter. This is actually only necessary, if the field name differs from the setter-name (according to standard java best practices). Usually, if you have a setter called setTheValue, the field theValue is altered. Unless you changed the field name with a @Property-Annotation, you do not need to do anything here... By rule of thumb: If you have a @Property-Annotation to your fields, you should also add the corresponding @UpdatingField-Annotation to the setter...

Actually, this sounds more complicated as it is ;-)

using the @PartialUpdate Annotation

The current version supports automate parial updates. You only have to add the @PartialUpdate Annotation to your class and off you go. Attention: there are some things you need to take care of:

when you use @PartialUpdate Annotation to your class definition, all instances created by reading this object from Mongo will be embedded in a proxy, which does take car of the partial updates for you (see above createPartiallyUpdateableEntity). This may cause problems with Reflection or .getClass()-Code When you create the object yourself, it's not partial updateable - you need to call createPartiallyUpdateableEntity manually

This mechanism relays on coding convention CamelCase, which means, setter need to be named after the property they set - for Example setName should set the property name and setLastName the property lastName (as usual) if you have a non-setter Method (like incSomething) which does modify a Property, you need to add the @PartialUpdate-Annotation to the method specifying the property, which will be changed after calling this, e.g.

@Entity
@PartialUpdate
class PUTest {
    private int counter;
    //getter do not change values - hence not interesting for PartialUpdates
    public int getCounter() {
       return counter;
    }
    //Setter Name follows coding convention -> will work fine
    public void setCounter(int c) {
        counter=c;
    }

    //as this modifies a field, but is not named according to the setter-rule, you need to specify 
    //the corresponding field
   @PartialUpdate("counter")
    public void inc() {
        counter++;
    }
}     

you can add the annotation to any method you like, the specified field will be add to the modified filed list accordingly it's not possible yet to specify more than one field to be changed or add the annotation more than once this code is not (yet) tested in conjunction with lazy loading - it might cause problems here dereferencing entities

Limitations

This code is rather new and not heavily tested yet, the code is implemented honoring maps, lists and embedded entities, but there is not Unit-Test for those cases jet. It does not work for embedded entities yet (and I'm not sure how to implement that feature - if you have ideas, just contribute).

You can’t perform that action at this time.