Realm-dotnet: Don't force objects to inheritance from RealmObject.

Created on 10 May 2016  路  35Comments  路  Source: realm/realm-dotnet

I'm a strongly adopted of Domain-Driven Design. Forcing objects to inheritance from RealmObject makes me unable to use DDD with RealM. Do a api for mapping objects like Entity Framework or MongoDB C# driver does.

O-Community T-Enhancement

Most helpful comment

We are planning to replace the base class with an attribute. The reason we kept it like this for now is that we don't support inheritance and covariance of realm objects, so the current solution is less risky that way. But we will change this.

All 35 comments

We are planning to replace the base class with an attribute. The reason we kept it like this for now is that we don't support inheritance and covariance of realm objects, so the current solution is less risky that way. But we will change this.

@kristiandupont An attribute will not solve the "issue" i'm talking about here. Because i'm gonna have to modify my Domain Entities anyway.

I see. So, the way the system works is that we modify the code of the classes that inherit from RealmObject. Now obviously we would not want to modify every single class in the project, so we need some sort of build-time tagging mechanism. Can you think of anything that would work in your scenario?

Unfortunately, those approaches rely on run-time configuration which won't work for us. We could come up with a solution that relies on attributes on a "module" class. However, with our current solution, assemblies are woven one at a time, so if you want your model assembly to be 100% free of realm code, we will need to enable cross-assembly weaving which is a non-trivial change.

Thanks, it was just an idea to be thought of, and added to your tools.

@kristiandupont Why run-time configurations won't work with RealM? Do you map the classes on compile-time?

@vinguan yes we do. We weave in code that modifies the behavior of automatic properties.

Andy thinks we will move to an interface because that allows us to use generics internally RealmList<T> where T : IRealmObject but this is still being debated.

I suggest we make use of Roslyn Source Generators once both Visual Studio and Xamarin Studio ship with a version of Roslyn that supports them. This means we'll ditch Fody, but I think this new implementation is going to be better.

I imagine models would look like this:

[RealmObject]
public partial class Person
{
    public string FullName { get; set; }
}

and using a Source Generator we'll be able to emit the following:

partial class Person : IRealmObject
{
    // members of IRealmObject
    public Realm Realm { get; set; }
    public RowHandle RowHandle { get; set; }

    replace string FullName
    {
        get
        {
            if (RowHandle == null)
            {
                return original;
            }

            return RealmObjectOps.GetStringValue(RowHandle, nameof(FullName));
        }
        set
        {
            if (RowHandle == null)
            {
                original = value;
            }
            else
            {
                RealmObjectOps.SetStringValue(RowHandle, nameof(FullName), value);
            }
        }
    }
}

This generation will run inside Roslyn itself, so the result will be visible to code analysis, users will be able to navigate to it in IDEs, the Realm APIs will be able to have generic constraints on IRealmObject where they now have them on RealmObject.

I think we shouldn't touch the current arrangement of having to inherit from RealmObject until Source Generators are available, though. To my mind, using the attribute only works best in this scenario.

I would prefer we migrate to using IRealmObject sooner than waiting for stable versions to ship with the Roslyn generators for reasons:

  1. It is a current pain point and stops some portion of users adopting Realm.
  2. Using an interface explicitly may continue to be something people prefer rather than having the _magic_ of it woven because they use an attribute. In particular, if they use other source code analysis tools for quality assurance, those will need to know an interface is being used.

@AndyDentFree: wouldn't this mean users will have to write a ton of boilerplate to implement the interface? There's a lot more in RealmObject that will have to move to IRealmObject - my sample here is only for illustrative purposes.

If I understood Andy he wants it to be like done in Java https://realm.io/docs/java/latest/#realmmodel-interface

So if I understand it correct, this Interface is actually empty so you don't have to implement any methods.
I don't underdtand how this would work in c# that you could access static methods from the object

I'm biased about the persistance Magic be down hidden or not. I think the idea using Roslyn has some charme.

I haven't completely worked through all implications, if I had it would be a PR ;-)

I was thinking of a combination of:

  1. Declaring the class as inheriting an (effectively empty) interface.
  2. Weaving in any extra properties needed, which are currently in RealmObject but want to reduce them a bit more anyway.
  3. Use extension methods on the interface if we need to add logic.

Yeah, I think the empty interface will work if we want to implement this before we have Source Generators at our disposal.

It would be important that even if you switch later on to Code generatione, that existing code by then will be easy to update

@escamoteur: we'd be able to provide a Code Fix 馃榾

+1 for Entity Framework Core support

Anything new on this?

Any news on this? This change will really empower the project I am looking to undertake. Having to inherit from RealmObject leaves me dead in the water for supporting Realm. Definitely vote going the interface route.

I would also love to see this fixed. In the meantime, using technologies like _AutoMapper_, might solve the problems you face.

+1 for interface

+10 for interface

+1 for interface, but to add something: this would solve the difficulties around using Cocoa Bindings in Xamarin.Mac, for what thats worth :), since you can have your data models inherit from NSObject and implement the hypothetical IRealmObject interface: see https://github.com/realm/realm-dotnet/issues/528

Hi, any news about Fluent API for realm-dotnet?

What do you mean by Fluent API?

@nirinchev I mean like Fluent API for EF Core
screen shot 2017-08-17 at 12 28 56

It can be very practical to have a pure model without attributes(decorators) or inheritance

Right. Realm's schema must be known at compile time, which is why fluent API syntax like EF Core is not feasible at the moment. We may investigate it at a later point, but relaxing the inheritance requirements is higher on our TODO list.

What are the benefits of not specifying attributes on your model that you're most interested in?

@nirinchev this will make the models more general between projects in which there may or may not be different attributes(depends on project dependencies).

Understood. When we do get to it, it will likely still be compile-time check (i.e. you won't be able to determine at runtime if a property is primary key or not), but at least you'll be able to do it at a centralized place as opposed to in each model definition. In the meantime an ugly solution would be to use #if clauses:

public class  MyObject : RealmObject
{
    #if MyProject1
    [PrimaryKey]
    #endif
    public int SomeIntValue { get; set; }

    #if MyProject2
    [Indexed]
    #endif
    public DateTimeOffset Date { get; set; }
}

@nirinchev thanks for the help

Looks like this is on the P2 backlog, is there a broad target timeline there? And is it leaning interface or attribute? Thanks!

We no longer use those labels (I had forgotten to remove it), but you're right - it's not our immediate priority, which means that it's unlikely to land in the next month. After that, we'll reevaluate our options and decide which issues would bring the most value to the community and focus on those.

At the moment, we don't lean toward either option as we haven't done enough research yet - everyone on the team has their gut feelings/preferences but those are in no way indicative of the direction we're going to take. Once we prioritize the issue, we'll weigh the pros and cons of each approach and go with whatever feels the best. In the meantime, everyone from the community is more than welcome to share their perspective. We're definitely taking your comments into account, so if you think one is better than the other, do let us know why - it increases its chances to get chosen.

I had a go, getting Realm working with an existing class hierarchy based on an internal library/framework. The issues that stopped me and some workarounds included:

  1. A bunch of private or internal members that were needed to work around Realm DotNet weaving assumptions. These were worked around by using Reflection as it was easier than building a custom library.
  2. The lack of support for inheritance which really surprised me as it wasn't clear in the documentation I had read to date. This really needs to be a headliner item of information though maybe just me assuming to much. This was worked around by flattening the hieararchy so the mapping is to the various base classes of the domain model classes.
  3. Assumptions that the DotNet type system is the source of the schema definition. This was worked around by building up a RealmSchema/ObjectSchema/Property hierarchy.
  4. Assumptions in the Realm DotNet library that schema information and the DotNet type system are tightly inter-dependent.

The last item is what stopped me from proceeding. It would make it a lot easier to use Realm DotNet classes that don't use the IL weaving system if:
a) The RealmObject.Metadata type "style" functionality is promoted to be a public concept in the API.
b) The bulk of the dotnet api uses the ObjectSchema concept rather than the dotnet Type class i.e. no assumption that the domain model Type is tightly bound to the schema.
c) There are specialized classes in the dotnet api which work assume the dotnet Type system is in play e.g. WeavedRealmObject works with dotnet Types but its base class RealmObject only works with ObjectSchema concepts.

This approach would allow the existing Weaved Realm object approach to work as is but also allow third parties to derive from RealmObject and implement domain model class architectures that do not rely on the weaved RealmObject base class hierarchy approach. Third parties can then use interfaces, Roslyn, attributes or whatever they want without modifications to the Realm DotNet API.

Would Realm be interested in pursuing this approach as a direction for the DotNet API?
Let me know if you need further clarification on what is being proposed.

FYI: I looked at whether DynamicRealmObject could be used for this sort of apporach but couldn't figure it out.

Was this page helpful?
0 / 5 - 0 ratings