简体   繁体   中英

Multiple Inheritance (maybe Abstract class?) C# Entity Framework

The last weeks I have been working on the development of a database based on Entity Framework 6 (Code-First) on c# using Visual Studio 2015.

I'm currently working on all the options that inheritance offers to work with. At this point and following the standards of a database I should implement multiple inheritance with Primary Key. What this means? This means that I should implement a class that inherits from another class and have his own PK for identify him different from the parent class. At this point I could implement it with TPC, making the parent class abstract and not defining any PK on the parent. This is a sample of the code at this point (this works and I have tested it)

    public abstract class Person
    {

        public string Name { get; set; }
        public string LastName { get; set; }

    }

    [Table("Students")]
    public class Student : Person
    {

        [Key]public int Id_student { get; set; }
        public string code_s { get; set; }
        public virtual ICollection<Course> courses { get; set; }

    }

Then the standard I should follow to build my database requires me to implement another inheritance taking Student as the Parent and creating another class that inherits from Student. The first and stupid idea I had was to make it as simple as write

ChildOfChild : Student

But obviously it didn't work.

Then it come to my mind the possibility of make Student class Abstract, but when I declared the Student class Abstract it didn't let me instantiate it and seed the table. I'm not sure if there is any other way to do this, using abstract class or any other method that could be useful to develop this. If you didn't understand the problem I'm trying to solve this is the sample of code that I would like to have and works.

    public abstract class Person
    {

        public string Name { get; set; }
        public string LastName { get; set; }

    }

    [Table("Students")]
    public class Student : Person
    {

        [Key]public int Id_student { get; set; }
        public string code_s { get; set; }
        public virtual ICollection<Course> courses { get; set; }

    }

    [Table("ExchangeStudent")]
    public class ExchangeStudent : Student
    {

        [Key]public int Id_exchange { get; set; }
        public string HomeUniversity {get; set;}

    }

You can't have two primary keys. Student defines Id_student as primary key and then in ExchangeStudent you define Id_exchange as primary key. I would implement a property 'Id' in Person and get rid of the Id_student and Id_exchange properties.

    public abstract class Student : Person
    {
        [Key]public int Id_student { get; set; }        
    }

    public class LocalStudent : Student{

    }

    public class ExchangeStudent : Student
    {        
        public string HomeUniversity {get; set;}
    }

but i would think about something like

public class Student : Person
    {

        [Key]public int Id_student { get; set; }
        public string code_s { get; set; }
        public virtual ICollection<Course> courses { get; set; }
        public ExchangeInfo ExchangeInfo{get;set;}
    }


    public class ExchangeInfo : Student
    {

        [Key]public int Id_exchange { get; set; }
        public Student Student{get;set;}
        public string HomeUniversity {get; set;}    
    }

Can HomeUniversity sounds like an attribute of student? it will be more confortable to work with single table of student instead of making 2 selects from 2 tables, to find out who is really listening cources also how you will create link for tables like course to two tables Student and ExchangeStudent?

Will there be any Person that doesn't have an Id ? If not, give a Person an Id property. Define in your fluent API where you model the TPC that this Id is the primary key of your Students as well as your exchange students.

public class Person
{
    public int Id {get; set;
    public string Name { get; set; }
    public string LastName { get; set; }
}

public class Student : Person
{
    // the primary key is in the base class
    public string code_s { get; set; }
    public virtual ICollection<Course> courses { get; set; }
}

public class ExchangeStudent : Student
{
    // the primary key is in one of the base classes
    public string HomeUniversity {get; set;}
}

Your DbContext configures TPC as in this link

class MyDbContext : DbContext
{
    public DbSet<Student> Students {get; set;}
    public DbSet<ExchangeStudent> ExchangeStudents {get; set;}

    protected override OnModelCreating(...)
    {   // configure Student and ExcahngeStudent as TPC,
        // if needed define primary key
        modelBuilder.Entity<Student>()
        .HasKey(student => student.Id)
        .Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("Students");
        });

        modelBuilder.Entity<ExchangeStudent>()
        .HasKey(student => student.Id)
        .Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("ExchangeStudents");
        });
    }

I'm not sure if HasKey is needed. Because the primary key follows the naming conventions , it might be that it is not needed.

The advantage of using fluent API above the use of attributes is that it gives you freedom to use the same classes and queries in a different database model, just by specifying a different DbContext.

From my understanding you want two tables where both with their own primary keys and a foreign key to define a one to one relationship. In your C# code you want these tables to have an inheritance relationship.

The only way I can see you doing this with Entity Framework is to split your requirements. Firstly create the Database models that represent the table structure you want.

namespace DAO
{
    public abstract class Person
    {
        public string Name { get; set; }
    }

    public class Student
    {
        public int StudentId { get; set; }
        public string Nickname { get; set; }
    }

    //Use navigation property rather than inheritance to define the relationship
    public class ExchangeStudent 
    {
        public int ExchangeStudentId { get; set; }
        public string HomeUniversity { get; set; }
        public virtual Student Student { get; set; }
    }
}

This gave me the following code:

 public override void Up()
        {
            CreateTable(
                "dbo.ExchangeStudent",
                c => new
                    {
                        ExchangeStudentId = c.Int(nullable: false, identity: true),
                        HomeUniversity = c.String(),
                        Student_StudentId = c.Int(),
                    })
                .PrimaryKey(t => t.ExchangeStudentId)
                .ForeignKey("dbo.Student", t => t.Student_StudentId)
                .Index(t => t.Student_StudentId);

            CreateTable(
                "dbo.Student",
                c => new
                    {
                        StudentId = c.Int(nullable: false, identity: true),
                        Nickname = c.String(),
                        Name = c.String(),
                    })
                .PrimaryKey(t => t.StudentId);

        }

Now if you need to have a inheritance relationship between Student and ExchangeStudent you can create new objects to define in a different namespace

namespace BusinessObject
{
    public abstract class Person
    {
        public string Name { get; set; }
    }

    public class Student
    {
        public int StudentId { get; set; }
        public string Nickname { get; set; }
    }

    //ExchangeStudent derives from Student
    public class ExchangeStudent : Student
    {
        public int ExchangeStudentId { get; set; }
        public string HomeUniversity { get; set; }
    }
}

Then you just need to create a class that maps the two objects. There are 3rd party libraries that can do this for you as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM