Saving EXISTING object gets FAULT = 'Server.Processing' exception during method invocation

Hi, I’m aware of several other threads relating to the server.processing exception during method invocation issue. Most of those issues were related to people not adding relations in the new way required in 4.x. I have a different issue in that I’m getting this fault when trying to save an existing object.

I shouldn’t have to do a setrelation again on an existing object do I? I really hope not because that would seem extremely backwards to me.

Steps to reproduce:

  1. Save object that has a 1:1 relation with BackendlessUser
    2 ) Set the relation after saving the object
  2. Save the existing object with the user relation set (just save with the object you get from a find)
  3. BOOM fault

Observations.
Currently, if I go and set the user field to nil right before I save the existing object again, it goes through and I have to do another setrelation again. This is definitely a dangerous workaround as now one step save has turned into 2 where if something happens to the network in between, I’ll potentially have an orphaned object with no user relation.

Please advise. I’m on 4.0.10 iOS SDK.

Thanks!

Hi Allen,

Since the version 4 was released you have to set relations between tables using separate methods (setRelation, addRelation, deleteRelation). It is the only way to manage relations.
Here you can find the documentation.

Regards Ilya

Thanks Ilya,

I’m aware of the need to setrelations in version 4. I am doing so for all NEWLY created objects. What the docs don’t seem to mention is how and if this applies to updating or saving EXISTING objects.

For example say I have an object Post with a 1:1 relation to BackendlessUser named author.

  1. I create and save Post
  2. I create and save BackendlessUser
  3. Set relation between post and author
  4. Change some content on Post
  5. How am I supposed to save the changes to Post now? It exists, the relation is set and the author field is populated with an instance of BackendlessUser

Currently, if I just do a save at step 5, I get the server.processing response. Is this somehow the expected behavior?

Am I seriously supposed to set the author to nil before doing an update/save and setrelation AGAIN?

I see that I misunderstood you firstly, sorry.
Let me check if I got everything properly this time.

  • You get an exception when trying to update existing object Post with not empty field ‘author’.
  • When you set it to null before saving, everything works properly but you afraid it will remove existing relation
    Is it correct?

Yes that’s correct Ilya, thanks. I wanted to clarify what exactly is the proper way to handle this or basically how it was designed to work in the first place, so I can understand what the right way is going about it or if this is an actual bug.

Thanks!

The system is designed to complete ignore any related properties when you either initially save an object or update an existing object. All operations managing the state of a relation are done exclusively via dedicated methods (add/set/removeRelation).

Regards,
Mark

Thanks for the reply Mark. That’s how I assumed it was designed to work. This means the fault response should be a bug correct?

Yes, it should not bomb out. I will open a ticket to verify this behavior.

Regards,
Mark

Thanks!

Hello Allen,

Could you please provide your code sample because everything works fine for me.

Here are my tests:

id<IDataStore>postStore = [backendless.data of:[Post class]];
id<IDataStore>userStore = [backendless.data of:[BackendlessUser class]];

Sync (results on screenshot1)

// Creating a new Post
Post *post = [Post new];
post.name = @"Post1";
Post *savedPost = [postStore save:post];
NSLog(@"New Post saved: %@", savedPost.name);


// Creating a new Backendless User
BackendlessUser *user = [BackendlessUser new];
user.name = @"User1";
user.email = @"user1@test.com";
user.password = @"111";
BackendlessUser *savedUser = [userStore save:user];
NSLog(@"New Backendless User saved: %@", savedUser.name);


// Setting the relation    
NSString *postObjectId = [backendless.data getObjectId:post];
NSNumber *setRelation = [postStore setRelation:@"author" parentObjectId:postObjectId childObjects:@[user.objectId]];
NSLog(@"Relation has been set: %@", setRelation);


// Updating Post   
post.name = @"Upated Post1";
[postStore save:post]; 
NSLog(@"Post updated: %@", post.name);

Async (results on screenshot2)

// Creating a new Post
Post *post = [Post new];
post.name = @"Post2";
[postStore save:post
       response:^(Post *savedPost) {
           NSLog(@"New Post saved: %@", savedPost.name);
       } error:^(Fault *fault) {
           NSLog(@"Error: %@", fault.message);
       }];


// Creating a new Backendless User
BackendlessUser *user = [BackendlessUser new];
user.name = @"User2";
user.email = @"user2@test.com";
user.password = @"111";
[userStore save:user
       response:^(BackendlessUser *savedUser) {
           NSLog(@"New Backendless User saved: %@", savedUser.name);
       } error:^(Fault *fault) {
           NSLog(@"Error: %@", fault.message);
       }];


// Setting the relation
Post *post = [postStore findFirst];
BackendlessUser *user = [userStore findFirst];
NSString *postObjectId = [backendless.data getObjectId:post];
[postStore setRelation:@"author"
        parentObjectId:postObjectId
          childObjects:@[user.objectId]
              response:^(NSNumber *setRelation) {
                  NSLog(@"Relation has been set: %@", setRelation);
                    
                  post.name = @"Upated Post2";
                  [postStore save:post
                         response:^(Post *post) {
                             NSLog(@"Post updated: %@", post.name);
                         }
                            error:^(Fault *fault) {
                                NSLog(@"Error: %@", fault.message);
                            }];                    
              } error:^(Fault *fault) {
                  NSLog(@"Error: %@", fault.message);
              }];

Regards, Olga

Thanks for the testing Olga, I’ve been banging my head against my screen and can’t figure out why this is happening.

I created a new table Post specifically to test against this. I ended up making it almost mirror the schema of the other table that has been giving me the fault. I run the following code below and for the Post class it goes through fine, but for the Shorti class it gives me the fault. Can you verify if you see the same thing? And what would make one fault and the other not when the schema’s are identical?

You can test against my app: 08D73C6A-C7AB-BAD9-FFEA-DBFAAD5AEA00 I’ve attached the Shorti and Post classes I’m using.


id<IDataStore> postStore = [backendless.data of:[Shorti class]];
    id<IDataStore> userStore = [backendless.data of:[BackendlessUser class]];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @try{
            // Creating a new Post
             Shorti *post = [Shorti new];
             post.descrip = @"Post1";
             Shorti *savedPost = [postStore save:post];
             NSLog(@"New Post saved: %@", savedPost.descrip);
             
             // Creating a new Backendless User
             BackendlessUser *user = [BackendlessUser new];
             user.name = @"User1";
             user.email = @"user1@test.com";
             user.password = @"111";
             BackendlessUser *savedUser = [userStore save:user];
             NSLog(@"New Backendless User saved: %@", savedUser.name);
             
             // Setting the relation
             NSString *postObjectId = savedPost.objectId;
             NSNumber *setRelation = [postStore setRelation:@"user" parentObjectId:postObjectId childObjects:@[savedUser.objectId]];
             NSLog(@"Relation has been set: %@", setRelation);
             
             // Updating Post
             savedPost.descrip = @"Updated Post1";
             savedPost = [postStore save:savedPost];
             NSLog(@"Post updated: %@", savedPost.descrip);
             
             DataQueryBuilder *queryBuilder = [[DataQueryBuilder alloc] init];
             [queryBuilder setWhereClause:[NSString stringWithFormat:@"user.objectId = '%@'", savedUser.objectId]];
             [queryBuilder setRelated:@[@"user"]];
             [queryBuilder setRelationsDepth:1];
             [queryBuilder setSortBy:@[@"created DESC"]];
             [queryBuilder setPageSize:100];
             
             NSArray<Shorti*> *result = [postStore find:queryBuilder];
             Shorti *existingPost = [result firstObject];
             
             existingPost.descrip = @"Updated again!";
             [postStore save:existingPost];
             NSLog(@"Updated again!");
            
        } @catch(Fault *fault){
            NSLog(@"FAULT: %@", fault);
        }
});

Thanks!

shorti classes.zip (4.84kB)

Hello Allen,

We’ll investigate this issue and answer you as soon as possible.

Regards, Olga

Hi Allen,
We’ve investigated the problem and found that it’s related to the object with cyclic relations being sent to the afterFind handler. The task with ID BKNDLSS-15799 has been created and we’ll get back to you when we have any further news.

Hi Allen,

The problem has been fixed.