0..1 to 1 Relationships in Entity Framework

Occasionally, I run into something that seems so fundamental that I'm surprised I've never encountered it before. Today, I just had one of those moments. I needed to model a 0..1 to 1 relationship (which apparently I've never needed to do before in over 3 years of working with EF) and ran into a weird issue. I was trying to create an actual foreign key property for the dependent entity and EF started spitting "Multiplicity is not valid" errors when I tried to generate a migration.

After a little research, I found the source of the issue. When you have a required:optional relationship, EF actually creates the foreign key on the primary key. In other words, the actual identifier for the dependent entity must be the identifier of the principal entity. Looked at another way:

public class Principal
{
    public int PrincipalId { get; set; }
    public virtual Dependent Dependent { get; set; }
}

public class Dependent
{
    // No key property. WTF?!

    [Required]
    public virtual Principal Principal { get; set; }
}

What's happening under the hood is that EF is creating a primary key for the dependent table itself, but importantly, it's not using an identity type. Instead, it's backfilling the id with the primary key of the related entity, instead. Why does EF do this? Well, the answer is quite simple: the EF team has simply neglected to implement unique indexes since the beginning until this day.

A one-to-one, principally, requires a concept of "uniqueness". That's really the only thing that makes it different, at least from the relational database side, from a one-to-many. Since, EF is incapable of handling unique indexes, the EF team side-stepped the issue entirely by enforcing the unique nature of the one-to-one via reliance on the primary key. By using the primary key as the foreign key, it's inherently unique. In other words, they chose to completely jack with how the relationship should be model and is modeled in countless production databases across the world, simply because they never felt like tackling unique indexes over the 10+ year span of EF's life. I apologize if that sounds bitter, but it kind of is, actually. I've been bitten by one eccentricity or another with Entity Framework since I started using it, and it almost invariably goes back to the team simply not implementing core relational database functionality. Now, I see them making the same mistakes, if not sometimes worse mistakes with EF Core, and I'm honestly about ready to call it quits with any ORM from any company named Microsoft.

There's countless open-source, free-as-in-beer ORMs out there, in all kinds of languages, that can and do get this stuff right - all this stuff right. Yet, one of the largest companies in the world can't produce an ORM that implements something as basic as unique indexes to model a one-to-one? Seriously? </rant>

With that out of my system. I honestly don't have much advice for anyone stumbling across this because they encountered the same issue. You can stop using Entity Framework, I guess. Or, accept the rather obtuse database modeling it forces upon you and move on. Unfortunately, in my case, neither of those are really acceptable options at this point, so I'll likely have to resort to using a one-to-many and enforcing the one-to-one nature via code, which isn't pretty, but I guess neither is life.

comments powered by Disqus