1.初始准备

1.1 工具准备
	开发软件:VisualStudio2022,EFCore6.0
	.net Core版本:.Net6.0
	数据库:mysql8.0
	数据库管理软件:Navicat
1.2 新建一个控制台程序

并按照前面的学习内容,在程序包管理控制台里 安装 Microsoft.EntityFrameworkCore.Tools
在这里插入图片描述
安装 Pomelo.EntityFrameworkCore.MySql
在这里插入图片描述

1.3 设计如下实体类
  public class Student
    {
           public int StudentId { get; set; }
           public string Name { get; set; }
           public string Sex { get; set; }
           public int Age { get; set; }
    }
	 public class Teacher
    {
        public int TeacherId { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }
    }
	public class Course
    {
        public int CourseId { get; set; }
        public string Name { get; set; }
        public Teacher Teacher { get; set; }
    }
	public class StudentAddress
    {
        public int StudentAddressId { get; set; }
        public string Address { get; set; }
        public string City { get; set; }

    }

2.实体对应关系

2.1 一对一

在上述实体关系中,一个学生只能由一个固定的地址,那么学生和地址是一对一的关系。而学生可以选择多个课程,学生和课程是多对多的关系。修改Student类如下:

  public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
        
        //导航属性
        public StudentAddress Address { get; set; }
        public IList<Course> Courses { get; set; } = new List<Course>();


    }
 public class StudentAddress
    {

        public int StudentAddressId { get; set; }
        public string Address { get; set; }
        public string City { get; set; }

        //导航属性
        public int StudentId { get; set; }
        public Student Student { get; set; }

    }
2.2 一对多

一个老师可以教授多门课程,老师和课程是一对多的关系。

  public class Teacher
    {
        public int TeacherId { get; set; }
        public string Name { get; set; }
        public string Title { get; set; }

        public IList<Course> Courses { get; set; } = new List<Course>();
    }
2.3 多对多

一个学生可能选择多门课程,一个课程也可以被多个学生同时选择。修改Course类如下:

   public class Course
    {
        public int CourseId { get; set; }
        public string Name { get; set; }

        //导航属性 
        public Teacher Teacher { get; set; }
        public IList<Student> Students { get; set; } = new List<Student>();
    }
2.3 在 DbContext类里配置相关对应关系

在项目中新建一个名为EFLearnDbContext,并继承于DbContext

public class EFLearnDbContext: DbContext
    {
        public EFLearnDbContext()
        {
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
          
           optionsBuilder.UseMySql("server=192.168.0.106;database=EFCoreLearn;user=root;password=123456", Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.28-mysql"));
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            #region 基本配置
            modelBuilder.Entity<Student>().Property(x => x.StudentId).ValueGeneratedOnAdd();//设置Id自增
            //设置姓名最大长度为50,字符为unicode,不能为空
            modelBuilder.Entity<Student>().Property(x => x.Name).HasMaxLength(50).IsUnicode().IsRequired();
            //设置性别最大长度为5 字符为Unicode,不能为空
            modelBuilder.Entity<Student>().Property(x => x.Sex).HasMaxLength(5).IsUnicode().IsRequired();
            //一对一只需要配置一个类就行了,
            modelBuilder.Entity<Student>().HasOne(x => x.Address).WithOne(x => x.Student).HasForeignKey<StudentAddress>(ad=>ad.StudentId);
            #endregion

            #region  Course
            modelBuilder.Entity<Course>().Property(x => x.Name).HasMaxLength(50).IsUnicode();
            //课程一对一
            modelBuilder.Entity<Course>().HasOne(x => x.Teacher).WithMany(t => t.Courses);
            modelBuilder.Entity<Course>().HasMany(x => x.Students).WithMany(st => st.Courses);
            #endregion

            #region Teacher配置
            modelBuilder.Entity<Teacher>().Property(x => x.Name).HasMaxLength(50).IsUnicode();
            modelBuilder.Entity<Teacher>().Property(x => x.Title).HasMaxLength(50).IsUnicode();
            #endregion

            #region 配置地址
            modelBuilder.Entity<StudentAddress>().Property(x=>x.City).HasMaxLength(100).IsRequired().IsUnicode();
            modelBuilder.Entity<StudentAddress>().Property(x=>x.Address).HasMaxLength(500).IsRequired().IsUnicode();
            #endregion
            
        }


        public DbSet<Student> Students { get; set; }
        public DbSet<Teacher> Teachers { get; set; }
        public DbSet<Course> Courses { get; set; }
        public DbSet<StudentAddress> Addresses { get; set; }
    }

如上所示,我们总结如下:

  • 在配置对应的时候,我们只配置一方就好了,另外一方不需要配置,即使你重复配置了也不会出错。
  • 在配置一对多的时候,我们最好从多的方面下手,采用HasOne(…).WithMany(…)的方法比较简单和容易理解。
  • 在传统的关系数据库中,配置多对多的时候,我们需要第三方的中间表进行相关联,但是在EFCore6.0以上时,我们只需要配置相关的导航属性后,设置HasMany(…).WithMany(…)进行配置,EFCore自己生成相关的中间表
  • 建议在设置对应关系的时候,如果为集合,最后给个初值化值。例如:public IList Students { get; set; } = new List()

3.生成数据库,查询相关ER关系

在程序包管理控制台输入 Add-Migration Initial
在这里插入图片描述
然后输入 Update-Database
在这里插入图片描述

然后打开数据库查看相关数据表的ER关系图,
在这里插入图片描述

同样的在多对多关系中,Courses和Students 出现了一个新表为 coursestudent,表结构中有主外键关系约束,除此之外,在删除时是级联关系的。
在这里插入图片描述

4.体验CURD

4.1添加数据

在Program.cs里添加如下代码

  //1.添加一些数据

    Course course1 = new Course() { CourseId = 3001, Name = "高等数学" };
    Course course2 = new Course() { CourseId = 3002, Name = "计算机原理" };
    Course course3 = new Course() { CourseId = 3003, Name = "操作系统原理" };
    Course course4 = new Course() { CourseId = 3004, Name = "编译原理" };

  
    Teacher teacher1 = new Teacher() { TeacherId = 10001, Name = "张教授", Title = "教授" };
    Teacher teacher2 = new Teacher() { TeacherId = 10002, Name = "王讲师", Title = "讲师" };
   
    teacher1.Courses=new Course[] { course1,course2 };
    teacher2.Courses = new Course[] { course3, course4 };

    dbContext.Teachers.AddRange(teacher1, teacher2);

    StudentAddress Address1 = new StudentAddress()
    {
        StudentAddressId = 37001,
        Address = "北京朝阳区",
        City = "北京",
    };

    StudentAddress Address2 = new StudentAddress()
    {
        StudentAddressId = 37002,
        Address = "上海徐汇区",
        City = "上海",
    };

    StudentAddress Address3 = new StudentAddress()
        {
        StudentAddressId = 37003,
            Address = "广州白云区",
            City = "广州",
        };

   

    Student student1 = new Student()
    {
        StudentId = 2022001,
        Name = "王二小",
        Age = 19,
        Sex="男",
        Address =Address1,
        Courses = new Course[] {course1, course2, course3 },

    };

    Student student2 = new Student()
    {
        StudentId = 2022002,
        Name = "张小五",
        Age = 20,
        Sex = "男",
        Address = Address2,
        Courses=new Course[] { course1,course2 },
    };

    Student student3 = new Student()
    {
        StudentId = 2022003,
        Name = "刘小花",
        Age = 20,
        Sex="女",
        Address = Address3,
        Courses = new Course[] { course1, course3 },

    };
    dbContext.Students.AddRange(student1, student2,student3);
    
    dbContext.SaveChanges();

AddRange()是批量添加,如上所示,在上面的例子中,我们只需要根据对应关系添加数据,在dbContext里添加对应关系的一方的就可以了,打开数据库后,可以发现数据顺利添加在其中。例如上面我们并没有调用dbContext.Addresses.Add()等方法,但是地址信息还是顺利写入了地址表。
在这里插入图片描述
在这里插入图片描述

4.2查询数据
 	var students= dbContext.Students.ToList();
    foreach (var st in students)
    {
        Console.WriteLine($"StudentId:{st.StudentId},Name:{st.Name},City:{st.Address.City}, Address:{st.Address.Address}");
    }

上述代码运行的时候,会报错提示NullReference,主要的原因是此时Address的属性为空,这说明在普通的查询中,导航属性并不能正确的加载。
在这里插入图片描述
将代码修改如下:

 var students= dbContext.Students.Include(x=>x.Address).ToList();

    foreach (var st in students)
    {
        Console.WriteLine($"StudentId:{st.StudentId},Name:{st.Name},City:{st.Address.City}, Address:{st.Address.Address}");
    }

发现可以正确显示结果,所以在包含导航属性查询的时候,可以使用Include方法进行相关的导航属性加载。
在这里插入图片描述
Include可以连续包含多个属性,添加如下代码,我们将Address和Courses都查询出来

var students= dbContext.Students.Include(x=>x.Address).Include(x=>x.Courses).ToList();

    foreach (var st in students)
    {
        Console.WriteLine($"StudentId:{st.StudentId},Name:{st.Name},City:{st.Address.City}, Address:{st.Address.Address},Courses:{string.Join(",",st.Courses.Select(x=>x.Name))}");
    }

在这里插入图片描述

4.3 删除数据
 #region 删除数据
    var st = dbContext.Students.Single(x => x.StudentId == 2022001);

    dbContext.Remove(st);
    dbContext.SaveChanges();
 #endregion

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图将学号为2022001的学生删除后,发现相关的地址信息,以及选择的课程信息也被删除了,这是由于在设置的EFCore默认了删除的行为为级联的方式。

EFCore 从入门到精通-3(模型创建)
EFCore 从入门到精通-5(谈谈迁移)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐