Update a list with existing elements throughs exception

Hi,

I have a question regarding updating an entry in a write operation with data already existing in the database but provided from outside. Consider this:

public class Game : RealmObject
{
    [PrimaryKey] long Id { get; set; }
    public ISet<User> Players { get; }
    /*  Other Properties  */
}

public class User: RealmObject
{
    [PrimaryKey] long Id { get; set; }
    public string Name { get; set; }

    [Backlink(nameof(Game.Players))]
    public IQueriable<Game> Games { get; }
}

Now, I want to update the Game Object with new Data, including new Users:

realm.write( () =>
{
/* This code does not work */
    // myPlayer comes from a different method and is not retrieved from the database
    if ( !myGame.Players.Contains( myPlayer ) )
        myGame.Players.Add(myPlayer);    // <-- this is the problem code

/* This code works */
    if ( !myGame.Players.Contains( myPlayer ) )
    {
        var player = realm.Find<User>( myPlayer.Id ) ?? myPlayer;
        myGame.Players.Add( player );
    }

/* This code should work as well */
    var game = myGame.GetDeepCopy();
    game.Players.Add( myPlayer );  
    realm.Add( game, update:true );
});

The problem arises when the user is not yet a player for the game and gets added, but already exists in the database. I get the player from a different source, not from the database. I know the name and id correctly, that is not a problem. All I want is to add it to the game. But that will through an exception for an already existing primary key.

If I search for the player by Id and add the realm object instead it works. But since I know that the player is not modified in any way and it only gets added to the Player list of the game, retrieving this object is just needless overhead.

In my actual code, this would have to be done for multiple types with multiple objects each, so for one “Game” it would have to be done a dozen times, and for hundreds or even thousands of “Games”. So it would be quite a lot of overhead.

Right now I see only two ways of adding the player to the game in my example, either retrieve the objects and add those to the list or create a copy, add the non-realm object to the copy and upsert them to the realm database (I assume, didn’t test this version).

Does someone have a way to do this without any needless searches or copies?

Hi again @Thorsten_Schmitz,

When adding a user to a game the backlink that you’ve defined must add the user to the database too, if not already existing. This is the only way for the backlink to function at all.
Now, you can’t add multiple objects with the same primary key. They have to be unique.
So, in your case, when myGame.Players.Add realm searches for the user to link to and if not there it’ll add it. And if another user was already there with the same pk you get the error you mentioned.

You seem concerned with performance. Usually realm is quite fast on retrievals/reads. Have you profiled your application and found the hit to be considerable? If so, we’d be interested in seeing your results.

Overall, if your profiling shows considerable hits you could consider caching the users and only use those. This should allow your “different source” to return the same user instance which will prevent realm from adding it again.

Hi,

I haven’t profiled anything yet. I will see if I can add this.

I’m worried because it might end up being several hundred thousand or (worst case) even millions of lookups, all performed locally on phone or tablet. And the objects would be disgarded afterwards.

It will also make the code much more cluttered and I was hoping to avoid that somehow.

Caching is not an option because the data in my app will come from an external source and is parsed by my app. Returning a RealmObject for this would just move all those lookups to another function.

Also, this is part of a bigger update function. It’s basically abatch/bulk operation, so all those lookups are performed in that one function, and I would have to cache everything at once.

I need to see how I can improve performance by putting multiple update operations in one write, but I’m worried about syncronization between the update threads as I need to handle things like multiple thread trying to add the same new user.

The user is just for better storage and the backlink querrying. I could make it an EmbeddedObject, but I’m worried about memory usage. Using an EmbeddedObject would result in duplicate strings. And as they are much bigger that the long keys the database size might increase a lot, and I have to consider a database size of several Gb on fat32 Android systems. So I can’t just neglect memory usage either.

Backlinks in your case are the right choice. EmbeddedObjects are just duplication and it’d take time to update the “same user” in all games.
And I agree that caching those instances doesn’t sound a good fit for you.

About the code clutter, that should be easily fixed by a helper or extension method. So that from the surface your call would be a 1 line call.

Adding an object to a collection by PK is currently a functionality that we don’t support. You could open a feature request on the github repo of the .NET SDK.

Let’s talk about performance:
Yes, if you can do fewer writes with larger updates in each you’ll have some gains. In fact, this would create fewer Transactions hence less jumps back and forth between managed and unmanaged.
Lastly, I understand your concerns about possible hit in performance. But, in general, any performance conversation should be backed by profiled code. This is simply because, while theoretically an operation is slow in practice, it may almost be imperceptible to the users.

I hope this helps.