BackendlessFault{ code: '4018', message: 'Metadata key cannot be NULL.' }

Steps to reproduce:

  1. Fetch an object from Backendless
  2. Update the object’s property
  3. Try to save the object
    Backendless returns “Metadata key cannot be NULL” error.

Is there a related GeoPoint which is fetched through auto-load?

No, there isn’t any GeoPoint related.
Mark, sorry for the incomplete info in this ticket. In fact, there is a custom validation on “beforeUpdate” handler for a Driver entity, that throws this error if __meta key is not present.



Backendless.ServerCode.Persistence.beforeUpdate('Driver', function(req) {


    //update will not work properly without metadata
    if(!req.item.__meta) {
        throw new Backendless.ServerCode.Error(4018, "Metadata key cannot be NULL.");
    }
...

I implemented this because there is a custom logic for updating Driver’s relations such as Vehicles. And unless the __meta key is present, the relations are not updated properly. The question is: why Android SDK does not pass __meta key with update request?

Hi Kateryna,

Android SDK does not strip out the __meta key. When your app receives an object from the backend and then you send that object back to the server, the __meta key will stay in there. However, if your code creates a new instance of that class and then you save it to the server, the __meta key will not be there.

Regards,
Mark

Hello, Kateryna!

Android SDK passes __meta key if object has been retrieved properly. Maybe, the issue is caused by your clients’ code. Try to make a small test with the following code samples:

Backendless.Data.mapTableToClass( "Driver", Driver.class );
Driver myDriver = new Driver();
myDriver.setName( "saved driver" );
Driver savedDriver = Backendless.Data.of( Driver.class ).save( myDriver );
savedDriver.setName( "updated driver" );
Backendless.Data.of( Driver.class ).save( savedDriver );

And a sample with retrieving:

Backendless.Data.mapTableToClass( "Driver", Driver.class );
Driver myDriver = new Driver();
myDriver.setName( "saved driver" );
Driver savedDriver = Backendless.Data.of( Driver.class ).save( myDriver );
Driver foundDriver = Backendless.Data.of( Driver.class ).findById( savedDriver );
foundDriver.setName( "updated driver" );
Backendless.Data.of( Driver.class ).save( foundDriver );

Both of these samples should work correctly - you should be able to see “__meta” field in the event handler.
regards,
Alex

And what about a case when a Driver was not created on Android side and app fetches this driver? I debugged this case and this Driver does not contain metadata field.

Did you fetch a Driver object into an Android app or the server-side code?

A Driver object is created via REST and Android client fetches it.

What if you declare the following field in the Driver class:?

public String __meta;

Getter/setter too for this field?

No, if the field is public, the getter/setter methods are not needed.

Added __meta field and Backendless returns BackendlessFault{ code: ‘1155’, message: ‘Duplicate entry’ }

What about the server-code logic? Did it go further there?

Why I can’t update some specific properties of an object using custom class?
For example I want to update some data of existing Driver, so I call the following code:
Driver driver = new Driver();
driver.setObjectId(objectId of existed Driver);
driver.setName(“Name”);
Backendless.Persistence.save(entity);
In this case Backendless returns an error which says that I should fill all fields marked with not null constraint.
I can update some specific properties of an object only using Map syntax, like:
HashMap driver= new HashMap();
driver.put("___class", “Driver”);
driver.put("__meta", existedDriver.__meta);
driver.put(“objectId”, existedDriver.getObjectId());
driver.put(“Status”, existedDriver.Status);
Backendless.Persistence.of(“Driver”).save(driver)

When a column has a “not null” constraint, a value must be present when you save/update an object. In the case of the class, the property is there even if you do not assign value to it and the serialized value will be null. In case of HashMap, the property is not there and that’s why it works.

Yes, I see. It would be great to have update method in SDK for objects’ updating.

When there is a value for the “objectId” property, the “save” operation performs an update.

But in any cases I need to fill all properties/relations

Only those which are marked as required (“not null” in constraints).

When I try to update a property(relation):

DriverStatus status = new status;

HashMap driver = new HashMap();
driver.put("___class", “Driver”);
driver.put("__meta", mCurrentDriver.__meta);
driver.put(“objectId”, mCurrentDriver.getObjectId());
driver.put(“Status”, status);
Map savedPhoneBook = Backendless.Persistence.of(“Driver”).save(driver);

server returns this error: BackendlessFault{ code: ‘1155’, message: ‘Duplicate entry’ }