Search code examples
c#entity-frameworkdata-annotationstable-per-hierarchy

EF, Table per Hierarchy, property in abstract class


I'm wondering if I can use virtual properties defines in a base class (abstract) to create a link with an other concrete type.

For example :

public abstract class AbstractService
{
   public int Id {get;set;}

   public int? SiteId {get;set;}
   public virtual Site Site {get;set;}
}

public class StudyTeamService : AbstractService
{
   public int? RoleId {get;set;}
   public virtual Role Role {get;set;}
}


public abstract class AbstractSite
{
   public int Id {get;set;}

   public string Name {get;set;}
}

public class Site : AbstractSite
{
   public virtual ICollection<StudyTeamService> StudyTeamServices {get;set;}
}

I presume I have to add an annotation on the ICollection so that it know how to map correctly, but I can't find the correct one.

Do you guys have any idea ?

Seems that if I set [InverseProperty("Site")] on the ICollection, it crash with an error telling that the relation is not defined in the assembly...


Solution

  • I think the problem with your code is in

    public class Site : AbstractSite
    {
       public virtual ICollection<StudyTeamService> StudyTeamServices {get;set;}
    }
    

    since the relationship is between Site andAbstractService, not withStudyTeamService`.

    The code below works for me:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration;
    
    namespace StackOverflow
    {
    
        public abstract class AbstractService
        {
            public int Id { get; set; }
            public virtual Site Site { get; set; }
    
            public int SiteId { get; set; }
        }
    
        [Table("StudyTeamServices")]
        public class StudyTeamService : AbstractService
        {
            public virtual Role Role { get; set; }
        }
    
        public class Role
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
    
        public abstract class AbstractSite
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
        public class Site : AbstractSite
        {
            public virtual ICollection<AbstractService> StudyTeamServices { get; set; }
        }
    
        public class Context : DbContext
        {
            static Context()
            {
                Database.SetInitializer<Context>(null);
            }
    
            public DbSet<AbstractService> AbstractServices { get; set; }
            public DbSet<StudyTeamService> StudyTeamServices { get; set; }
            public DbSet<Site> Sites { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                //Not EdmMetadata Table on DB
                //modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
    
                modelBuilder.Configurations.Add(new AbstractServiceMap());
            }
    
        }
    
        public class AbstractServiceMap : EntityTypeConfiguration<AbstractService>
        {
            public AbstractServiceMap()
            {
                HasRequired(a => a.Site).WithMany(s => s.StudyTeamServices).HasForeignKey(a => a.SiteId);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var context = new Context();
                context.Database.Delete();
                context.Database.Create();
    
                var studyTeamService = new StudyTeamService();
                studyTeamService.Role = new Role { Name = "role1" };
                studyTeamService.Site = new Site { Name = "Site1" };
    
                context.StudyTeamServices.Add(studyTeamService);
                context.SaveChanges();
                Console.WriteLine("Done");
                Console.ReadLine();
            }
        }
    }