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

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

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

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

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

1to1.PNG

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

.net 中的对象关系实现

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

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

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

        /// <summary>
        /// 班级名称
        /// </summary>
        [StringLength(20)]
        public virtual int ClassName { get; set; }
        
        /// <summary>
        /// 1对1关系
        /// </summary>
        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; }

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

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

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

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

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

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

n对n.PNG

.net 中的对象关系实现

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

        public virtual int StudentId { get; set; }

        /// <summary>
        /// 1对1
        /// </summary>
        public virtual Student Student { get; set; }

        /// <summary>
        /// 1对1
        /// </summary>
        public virtual Course Course { get; set; }
    }

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

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

        /// <summary>
        /// 1对n
        /// </summary>
        public virtual ICollection<StudentCourse> StudentCourses { get; set; }
    }

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

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

        /// <summary>
        /// 1对n
        /// </summary>
        public virtual ICollection<StudentCourse> 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<StudentCourse>()             
                .HasKey(x => new { x.StudentId, x.CourseId }); 
        }

        public DbSet<Products> Products { get; set; }
        
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    }

添加迁移文件,执行迁移


migration-2.PNG

查看生成的StudentCourse表结构:


student_course_table.PNG

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 9,069评论 0 13
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,426评论 0 2
  • 一、上堂回顾 1.概念​ 数据库管理系统,数据库,表​ SQL的分类:DDL、DML、DQL、DCL2.数据库的使...
    WenErone阅读 434评论 0 0
  • 一、数据库操作 3.DQL 3.7分组查询 group by:分组查询 将字段中相同值归为一组having:...
    郑元吉阅读 304评论 0 0
  • 第十二章 高阶pandas 12.2 高阶GroupBy应用 12.2.1 分组转换和“展开”GroupBy 内...
    CCC考研阅读 886评论 0 15