Realm Xamarin v10.10.0 Release Notes

Release Date: 2022-02-28 // 3 months ago
  • Guid representation issue

    ๐Ÿš€ This release fixes a major bug in the way Guid values are stored in the database. It provides an automatic migration for local (non-synchronized) databases, but extra caution is needed when upgrading an app that uses Sync.

    Context

    ๐Ÿ‘€ A Guid is represented by 4 components - int, short, short, and a byte[8]. Microsoft's Guids diverge from the UUID spec in that they encode the first three components with the endianness of the system (little-endian for all modern CPUs), while UUIDs encode their components as big-endian. The end result is that the same bytes have a different string representations when interpreted as a Guid by the .NET SDK vs when interpreted as a UUID by the Realm Database - e.g. f2952191-a847-41c3-8362-497f92cb7d24 vs 912195f2-47a8-c341-8362-497f92cb7d24 (note the swapping of bytes in the first three components). You can see the issue by opening a database created by the .NET SDK in Realm Studio and inspecting the values for Guid properties.

    ๐Ÿ›  Fix

    ๐Ÿ”€ The fix we're providing is to adjust the behavior of the .NET SDK to read/write Guids to the database with big-endian representation. This means that the SDK and the database will consistently display the same values. This has some implications which are described in the Local- and Synchronized Realms sections.

    Local Realms

    โšก๏ธ For local Realms, we're executing a one-time migration the first time the Realm is opened with the new SDK. During this migration, we'll update all Guid fields to big-endian format. This means that their string representation will remain the same, but the value in the database will change to match it. This means that the upgrade process should be seamless, but if you decide to downgrade to an older version of the SDK, you'll see the byte order get flipped. The migration will not execute multiple times, even if you downgrade.

    ๐Ÿ”€ Synchronized Realms

    ๐Ÿ”€ There's no client migration provided for synchronized Realms. This is because the distributed nature of the system would mean that there will inevitably be a period of inconsistent state. Instead, the values of the Guid properties are read as they're already stored in the database, meaning the string representation will be flipped compared to previous versions of the SDK but it will now match the representation in Atlas/Compass/Realm Studio. There are three general groups your app will fall under:

    • If you don't care about the string values of Guid properties on the client, then you don't need to do anything. The values will still be unique and valid Guids.
    • โฌ†๏ธ If you do use the string guid values from the client app - e.g. to correlate user ids with a CMS, but have complete control over your client devices - e.g. because this an internal company app, then it's advised that you execute a one-time migration of the data in Atlas and force all users to upgrade to the latest version of the app.
    • โšก๏ธ If you can't force all users to update at the same time, you can do a live migration by adding an extra property for each Guid property that you have and write a trigger function that will migrate the data between the two. The old version of the app will write to the original property, while the new version will write to the new property and the trigger will convert between the two.

    โšก๏ธ If you are using sync and need to update to the latest version of the SDK but are not ready to migrate your data yet, see the Opting out section.

    Opting out

    ๐Ÿ›  If for some reason, you want to opt out of the fixed behavior, you can temporarily opt out of it by setting the Realm.UseLegacyGuidRepresentation property to true. This is not recommended but can be used when you need more time to test out the migration while still getting bugfixes and other improvements. Setting it to true does two things:

    1. It brings back the pre-10.10.0 behavior of reading/writing Guid values with little-endian representation. โช 1. It disables the migration code for local Realms. Note that it will not revert the migration if you already opened the Realm file when UseLegacyGuidRepresentation was set to false.

    โœจ Enhancements

    • Lifted a limitation that would prevent you from changing the primary key of objects during a migration. It is now possible to do it with both the dynamic and the strongly-typed API: csharp var config = new RealmConfiguration { SchemaVersion = 5, MigrationCallback = (migration, oldVersion) => { // Increment the primary key value of all Foos foreach (var obj in migration.NewRealm.All<Foo>()) { obj.Id = obj.Id + 1000; } } }
    • ๐Ÿšš [Unity] The Realm menu item in the Unity Editor was moved to Tools/Realm to reduce clutter and align with other 3rd party editor plugins. (Issue #2807)

    ๐Ÿ›  Fixed

    • ๐Ÿ›  Fixed an issue with xUnit tests that would cause System.Runtime.InteropServices.SEHException to be thrown whenever Realm was accessed in a non-async test. (Issue #1865)
    • ๐Ÿ›  Fixed a bug that would lead to unnecessary metadata allocation when freezing a realm. (Issue #2789)
    • ๐Ÿ›  Fixed an issue that would cause Realm-managed objects (e.g. RealmObject, list, results, and so on) allocated during a migration block to keep the Realm open until they are garbage collected. This had subtle implications, such as being unable to delete the Realm shortly after a migration or being unable to open the Realm with a different configuration. (PR #2795)
    • ๐Ÿ›  Fixed an issue that prevented Unity3D's IL2CPP compiler to correctly process one of Realm's dependencies. (Issue #2666)
    • ๐Ÿ›  Fixed the osx runtime path in the Realm NuGet package to also apply to Apple Silicon (universal) architectures (Issue #2732)

    Compatibility

    • Realm Studio: 11.0.0 or later.

    Internal

    • Using Core 11.10.0

Previous changes from v10.9.0

  • โœจ Enhancements

    • โž• Added support for a new mode of synchronization with MongoDB Realm, called "Flexible Sync". When using Flexible Sync, the client decides which queries it's interested in and asks the server for all objects matching these queries. The matching objects will be stored in a local Realm, just like before and can be queried and accessed while offline. This feature is in beta, so feedback - both positive and negative - is greatly appreciated and, as usual, we don't recommend using it for production workloads yet.
      • Added a new configuration type, called FlexibleSyncConfiguration. Use this type to get a Realm instance that uses the new synchronization mode with the server.
      • Deprecated the SyncConfiguration class in favor of PartitionSyncConfiguration. The two classes are equivalent and the new type is introduced to better contrast with FlexibleSyncConfiguration. The two types are equivalent and allow you to open a Realm instance that is using the old "Partition Sync" mode.
      • Added a new type, called SubscriptionSet. It is a collection, holding the various active query subscriptions that have been created for this Realm. This collection can be accessed via the Realm.Subscriptions property. It will be null for local and partition sync Realms and non-null for flexible sync Realms.

    A minimal example would look like this:

      var config = new FlexibleSyncConfiguration(user);
      var realm = Realm.GetInstance(config);
    
      // Add a new subscription
      realm.Subscriptions.Update(() =>
      {
        var year2022 = new DateTimeOffset(2022, 1, 1);
        var saleOrders = realm.All<SaleOrder>().Where(o => o.Created > year2022);
        realm.Subscriptions.Add(saleOrders);
      });
    
      // Wait for the server to acknowledge the subscription and return all objects
      // matching the query
      await realm.Subscriptions.WaitForSynchronizationAsync();
    
      // Now we have all orders that existed on the server at the time of
      // subscribing. From now on, the server will send us updates as new
      // orders get created.
      var orderCount = realm.All<SaleOrder>().Count();
    
    • Multiple subscriptions can be created for queries on the same class, in which case they'll be combined with a logical OR. For example, if you create a subscription for all orders created in 2022 and another for all orders created by the current user, your local Realm will contain the union of the two result sets.
    • Subscriptions can be named (which makes it easier to unsubscribe) or unnamed. Adding multiple unnamed subscriptions with the same query is a no-op.
    • Modifying the set of active subscriptions is an expensive operation server-side, even if the resulting diff is not large. This is why we recommend batching subscription updates as much as possible to avoid overloading the server instance. A good practice is to declare the user subscriptions upfront - usually the first time the Realm is opened, and only update them when absolutely necessary.
    • Find more information about the API and current limitations in the docs.

    Compatibility

    • Realm Studio: 11.0.0 or later.

    Internal

    • Using Core 11.8.0.
    • ๐Ÿš€ Release tests are executed against realm-qa instead of realm-dev. (PR #2771)