Search code examples
c#entity-frameworkodataasp.net-web-api2odata-v4

OData: Map inherited key using ODataConventionModelBuilder


Having these:

class Base
{
  public int ID {get;set;}
}

class DerivedA : Base
{
}

class DerivedB : Base
{
}

...

I can then set the common primary key like so:

builder.EntityType<Base>().HasKey(m => m.ID);

However, when I do so, EVERY derived type gets mapped which is undesirable for various reasons, one being that I have dozens of derived types. With patience, I've tried to ignore every single one of those I don't want, and I end up with this error:

The sequence contains more than one element
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
   at System.Web.OData.Builder.ODataConventionModelBuilder.RemoveBaseTypeProperties(StructuralTypeConfiguration derivedStructrualType, StructuralTypeConfiguration baseStructuralType)
   at System.Web.OData.Builder.ODataConventionModelBuilder.DiscoverInheritanceRelationships()
   at System.Web.OData.Builder.ODataConventionModelBuilder.GetEdmModel()

I do believe the ignores end up overlapping each other in some way. I just can't fine tune an ignore block for every single one of them. The only thing that worked so far is to redefine the ID property as new for each derived class, which pretty much defeats the whole purpose of the base class.

Any tip on that?


Solution

  • There's a lot to think about and one leftover I didn't see from many trial and errors is that in addition to the Base class's ID mapping, I also mapped the same ID for the derived classes:

    builder.EntityType<Base>().HasKey(m => m.ID);
    ...
    (in another class far far away)
    builder.EntityType<DerivedA>().HasKey(m => m.ID);
    builder.EntityType<DerivedB>().HasKey(m => m.ID);
    

    I removed the key mapping on the derived classes, left only the key mapping on the Base class, and everything worked. So I guess this had nothing to do with ignores.

    What a cryptic, generic error message...

    I updated a blog post with this new information, check it out for more information including how to ignore derived types.