Search code examples
c#asp.net.netentity-frameworkef-code-first

Entity Framework One to One or Zero to Itself


I feel like this is something I have figured about before, but can't seem to get past for days now. What I'm after is simple, a given user might have multiple relationships with other users nested within itself.

public class ApplicationUser : IdentityUser
{
   public virtual ApplicationUser Approver { get; set; }
   public virtual ApplicationUser Provider { get; set; }
}

Without getting errors about which end is principal and dependents, etc. A given user may not have an approver, or they may.

I feel like there was something about making derived classes:

public class Provider: ApplicationUser
{
    public virtual List<ApplicationUser> Clients{ get; set; }
}

Which would make the ApplicationUser like this:

public class ApplicationUser : IdentityUser
{
   public virtual Approver Approver { get; set; }
   public virtual ProviderProvider { get; set; }
}

With

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Provider> Providers { get; set; }
    public DbSet<Approver> Approvers { get; set; }
}

But getting mixed up with ForeignKey attributes for a derived class that shares the same properties/ids. I've done many searches but most of the posts are related to an ApplicationUser that has a one to one or zero relationship with another class such as AddressInfo. I need it to be the same nested class with Code First, favoring attributes to fluent when possible.

Different attempts at this provide various different errors, too many different scenarios to list the various errors.

Thanks for any recommendations!


Solution

  • Please read more about inheritance strategies in EF, for example here.

    If you want to add relation only between your users and all users will have the same properties, then you don't need to use any inheritance, but you need to help EF understand what you are doing:

     public class ApplicationUser
        {
            public virtual int Id { get; set; }
            public virtual string Name { get; set; }
    
            public virtual ApplicationUser Provider { get; set; }
            public virtual List<ApplicationUser> Clients { get; set; }
    
            public virtual ApplicationUser Approver { get; set; }
            public virtual List<ApplicationUser> Candidates { get; set; }
        }
    
    
        public class ApplicationDbContext : DbContext
        {
            public DbSet<ApplicationUser> Users { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.Entity<ApplicationUser>().HasOptional(e => e.Approver).WithMany(e=>e.Candidates);
                modelBuilder.Entity<ApplicationUser>().HasOptional(e => e.Provider).WithMany(e =>e.Clients);
            }
        }