Uploaded image for project: 'Realm .NET SDK'
  1. Realm .NET SDK
  2. RNET-596

Allow intercepting lifecycle events of a `RealmObject`/`EmbeddedObject`

    • Type: Icon: Improvement Improvement
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None

      Description

      For the sake of conciseness, I'll refer to both RealmObject and EmbeddedObject as RealmObject

      Workaround

      The current API does not provide a way for developers to execute code that is capable of interrupting the lifecycle of a RealmObject. Developers can only go as far as getting notified by the creation, modification, and removal of a RealmObject but are not able to stop the said events. This can be useful in scenarios where a validation is required before the said RealmObject can be created, modified, or removed from the database.

      Currently, a workaround I can think of for intercepting the lifecycle of a RealmObject is to create an additional abstraction layer over the Realm API by creating individual services for each type inheriting RealmObject that will manage how the record can be added, modified, or removed.

      The following is an example:

      Unable to find source-code formatter for language: csharp. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      public class ItemService {
          [Inject] 
          public Realm Realm { get; set; }
          public void Add( ... ) { }
          public void Remove( ... ) { }
          public void Modify( ... ) { }
      }
      

      Unfortunately, this pattern can only apply to a CRUD/monolithic approach and will not be able to scale once there are dozens of types inheriting RealmObject and can become difficult to maintain in complex scenarios that would better fit with a CQRS/microservices approach.

      Proposal

      My proposal is to use the command design pattern and provide abstraction classes or interfaces that can be inherited by developers which can later be registered in a Realm instance so that the Realm instance will execute it.

      The following is an example:

      Unable to find source-code formatter for language: csharp. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      // Interfaces provided by Realm
      public interface IOnCreate<T> where T : RealmObjectBase { public void OnCreate(T item); }
      public interface IOnModify<T> where T : RealmObjectBase { public void OnModify(T item); }
      public interface IOnDelete<T> where T : RealmObjectBase { public void OnDelete(T item); }
      
      // Sample Realm Object
      public class Item : RealmObject {
          [PrimaryKey]
          public Guid ID { get; set; }
          public string Name { get; set; }
      }
      
      // Sample interceptor
      public class ItemOnCreate : IOnCreate<Item> {
          public OnCreate(Item item) {
              if (string.IsNullOrWhitespace( item.Name ))
                  throw new Exception(); // this will stop the realm from adding the item
          }
      }
      

      The following is an example of how can the proposed API be used:

      Unable to find source-code formatter for language: csharp. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      public class Program {
          public void Main() {
              // Sample code when using the interceptor with the Realm API
              Realm realm = Realm.GetInstance();
              realm.AddInterceptor<ItemOnCreate>();
              
              // Sample code trying to write on the Realm
              using var transaction = realm.BeginWrite();
              var item1 = new Item() { ID = Guid.NewGuid(), Name = "Foo" };
              var item2 = new Item() { ID = Guid.NewGuid(), Name = "" };
              realm.Add( item1 ); // item1 is added to the temporary realm 
              realm.Add( item2 ); // item2 is added to the temporary realm, but this will not call the interceptor yet
      
              // once the transaction commits, realm will supply every added `Item` into the interceptor.
              // if an interceptor will throw an exception for one instance of a RealmObject, 
              // the ENTIRE transaction will instead rollback even if other added/modified/removed items were valid
              transaction.Commit();
          }
      }
      

      How important is this improvement for you?

      Dealbreaker

            Assignee:
            Unassigned Unassigned
            Reporter:
            unitosyncbot Unito Sync Bot
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: