-
Type: Improvement
-
Resolution: Unresolved
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
3 - M (<= 1 month)
-
2705
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:
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:
// 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:
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