efcore系列三 用efcore构建常见的关系类型

上一篇文章简单介绍了efcore查询的流程,在这篇文章会延续原项目,添加新的关系类型( •̀ ω •́ )。

在数据库中,常见的关系类型有三种:
1 对 1 例如:一个班级 有 一个班主任
1 对 n 例如: 一个班级 有n个学生
n对n 例如:一个学生可以选择多门课程,一门课程可以被多名学生选择

这里n 对 n关系比较难理解一点,需要结合具体的上下文分析,这里也是不使用原项目中的产品与订单来解释的原因。

1 对 1 关系的数据库实现:

1to1.PNG

从技术上看,这是1对0或1关系,首先A是一定存在的,B有可能存在,A拥有B。

.net 中的对象关系实现

    /// 
    /// 班主任
    /// 
    [Table("class_teacher")]
    public class ClassTeacher
    {
        public virtual int ClassTeacherId { get; set; }

        /// 
        /// 
        /// 
        [StringLength(20)]
        public virtual string TeacherName { get; set; }
    }

    /// 
    /// 班级
    /// 
    [Table("school_class")]
    public class SchoolClass
    {
        public virtual int SchoolClassId { get; set; }

        /// 
        /// 班级名称
        /// 
        [StringLength(20)]
        public virtual int ClassName { get; set; }
        
        /// 
        /// 1对1关系
        /// 
        public virtual ClassTeacher ClassTeacher { get; set; }
    }

1 对 n 关系的数据库实现:

1 对n关系同 1对1关系在数据库的实现上是一样的,都是这里通过B持有A的主键作为外键实现这种关系,A拥有B,区别是A拥有B的个数。

1对n.PNG

.net 中的对象关系实现

    [Table("student")]
    public class Student
    {
        public virtual int StudentId { get; set; }

        /// 
        /// 
        /// 
        [StringLength(20)]
        public virtual string StudentName { get; set; }
    }

    /// 
    /// 班级
    /// 
    [Table("school_class")]
    public class SchoolClass
    {
        public virtual int SchoolClassId { get; set; }

        /// 
        /// 班级名称
        /// 
        [StringLength(20)]
        public virtual int ClassName { get; set; }

        /// 
        /// 1对1关系
        /// 
        public virtual ClassTeacher ClassTeacher { get; set; }
    }

1 对 n 关系的数据库实现:

n 对 n 关系是无法用两张表来直接描述的,需要借助一张中间表。如上面的解释 n对n :一个学生可以选择多门课程,一门课程可以被多名学生选择,n对n 通过1 对 n 与 n对1 来描述。

n对n.PNG

.net 中的对象关系实现

    /// 
    /// 中间表
    /// 
    [Table("student_course")]
    public class StudentCourse
    {
        public virtual int CourseId { get; set; }

        public virtual int StudentId { get; set; }

        /// 
        /// 1对1
        /// 
        public virtual Student Student { get; set; }

        /// 
        /// 1对1
        /// 
        public virtual Course Course { get; set; }
    }

    [Table("student")]
    public class Student
    {
        public virtual int StudentId { get; set; }

        /// 
        /// 
        /// 
        [StringLength(20)]
        public virtual string StudentName { get; set; }

        /// 
        /// 1对n
        /// 
        public virtual ICollection StudentCourses { get; set; }
    }

    [Table("course")]
    public class Course
    {
        public virtual int CourseId { get; set; }

        /// 
        /// 
        /// 
        [StringLength(20)]
        public virtual string CourseName { get; set; }

        /// 
        /// 1对n
        /// 
        public virtual ICollection StudentCourses { get; set; }
    }

添加DbSet 并添加OnModelCreating方法指定StudentCourse的主键,StudentCourse为复合主键,直接生成迁移文件会报错,需要使用fluent API方式添加。这里只添加n对n关系结构所以ClassTeacher与SchoolClass表就不加进来了。

     public class AppDbContext:DbContext
    {
        private static string ConnStr;

        static AppDbContext()
        {
            var builder = new ConfigurationBuilder();
            builder.AddJsonFile("appsetting.json");
            var config = builder.Build();
            ConnStr = config["ConnectionString"];
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql(ConnStr);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)    
        {                                                 
            modelBuilder.Entity()             
                .HasKey(x => new { x.StudentId, x.CourseId }); 
        }

        public DbSet Products { get; set; }
        
        public DbSet Students { get; set; }
        public DbSet Courses { get; set; }
    }

添加迁移文件,执行迁移


migration-2.PNG

查看生成的StudentCourse表结构:


student_course_table.PNG

基本与预期结构一致,从KEY IX_student_course_CourseId (CourseId) 知道添加了一个普通索引CourseId ,这个其实可以不需要,可以在执行迁移前在生成的迁移文件中修改。

你可能感兴趣的:(efcore系列三 用efcore构建常见的关系类型)