EFCore 从入门到精通-8(再谈映射关系)

1.初始准备

开发软件:VisualStudio2022,EFCore6.0
.net Core版本:.Net6.0
数据库:mysql8.0
数据库管理软件:Navicat
按照前面的教程,安装相关的Nuget包,重新设计以下几个实体类

 public class Address
    {
        public int AddressId { get; set; }
        public string Street { get; set; }
        public string City { get; set; }


        //导航属性
        public int  PersonId { get; set; }
        public  Person Person { get; set; }
    }
    public class Person
    {
        public int  Id { get; set; }
        public string Name { get; set; }
        public string Sex { get; set; }

        public int Age { get; set; }


        public Address Address { get; set; }

    }
     public class Student:Person
    {
        public string Hobby { get; set; }
    }
     public class Teacher:Person
    {
        public string Title { get; set; }
    }

新建EFCoreLearnDbContext类,代码如下:

public class EFLearnDbContext:DbContext
    {
        public EFLearnDbContext()
        {
            this.Database.EnsureCreated();
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql("server=172.10.10.85;database=EFCoreLearn8;user=root;password=um-robotics", Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.28-mysql"));
            // optionsBuilder.UseLazyLoadingProxies();
            optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            #region Student基本配置

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

                //  entity.Navigation(x => x.Courses).AutoInclude();
                // entity.Navigation(x => x.Address).AutoInclude();
            });

            #endregion

      
            #region Teacher配置

            modelBuilder.Entity<Teacher>(entity =>
            {
                entity.Property(x => x.Name).HasMaxLength(50).IsUnicode();
                entity.Property(x => x.Title).HasMaxLength(50).IsUnicode();
            });

            #endregion

            #region 配置地址

            modelBuilder.Entity<Address>(entity =>
            {
                entity.Property(x => x.City).HasMaxLength(100).IsRequired().IsUnicode();
                entity.Property(x => x.Street).HasMaxLength(500).IsRequired().IsUnicode();
            });
            #endregion
            base.OnModelCreating(modelBuilder);
        }

        public DbSet<Person> People { get; set; } 
        public DbSet<Student> Students { get; set; }
        public DbSet<Teacher> Teachers { get; set; }
        public DbSet<Address> Addresses { get; set; }
    }

在Program里添加下面的代码


using EFCoreLearn8;
using EFCoreLearn8.Models;

using (EFLearnDbContext dbContext = new EFLearnDbContext())
{
    #region 【1】添加数据
   

    

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

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

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



    Student student1 = new Student()
    {
        Id = 2022001,
        Name = "王二小",
        Age = 19,
        Sex = "男",
        Address = Address1,
        Hobby = "打篮球",
       

    };

    Student student2 = new Student()
    {
        Id = 2022002,
        Name = "张小五",
        Age = 20,
        Sex = "男",
        Address = Address2,
        Hobby = "打乒乓球",
       
    };

    Student student3 = new Student()
    {
        Id = 2022003,
        Name = "刘小花",
        Age = 20,
        Sex = "女",
        Address = Address3,
        Hobby = "弹钢琴",
      

    };

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

    Teacher teacher1 = new Teacher() { Id = 10001, Name = "张教授", Title = "教授", Sex="男",Age=50,Address=Address1};
    Teacher teacher2 = new Teacher() { Id = 10002, Name = "王讲师", Title = "讲师",Sex="男", Age=48 ,Address=Address3};

    dbContext.Teachers.AddRange(teacher1, teacher2);
    dbContext.SaveChanges();
    #endregion
}

2.存储继承关系

上述代码中,Student 和Teacher是继承Person类来的,运行准备好的代码后,翻开数据库查看如下,表只有两个People和Address
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

其中可以发现Discriminator的这个字段我们并没有设置,而是EFCore是主动给我们加上去的,这个字段的英文意思是鉴别器、辨别者,而EFCore通过这个字段来确定到底是哪个继承类。
下面我们查询下,看看EFCore是否能够准确查询数据,同时我们打开logger,看下EFCore是如何查询的。

   var student= dbContext.Students.ToList();

在这里插入图片描述
查看logger可以知道,在查询的时候,EFCore会通过 Discriminator 作为一个筛选条件,这样就能够为我们选择正确的数据。

2.1 自由定义配置Discriminator

更改EFLearnDbContext类如下:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            #region Student基本配置

            modelBuilder.Entity<Person>(entity =>
            {

                entity.HasDiscriminator<int>("person_type")
                         .HasValue<Person>(0)
                         .HasValue<Student>(1)
                         .HasValue<Teacher>(2);
                entity.Property(x => x.Id).ValueGeneratedOnAdd();//设置Id自增
                entity.Property(x => x.Name).HasMaxLength(50).IsUnicode().IsRequired();//设置姓名最大长度为50,字符为unicode,不能为空                                                   
                entity.Property(x => x.Sex).HasMaxLength(5).IsUnicode().IsRequired();//设置性别最大长度为5 字符为Unicode,不能为空                                                                   
                entity.HasOne(x => x.Address).WithOne(x => x.Person).HasForeignKey<Address>(ad => ad.PersonId);//一对一只需要配置一个类就行了,

                //  entity.Navigation(x => x.Courses).AutoInclude();
                // entity.Navigation(x => x.Address).AutoInclude();
            });

然后删除DbSet 中的Student 和Teacher

  public DbSet<Person> People { get; set; } 
  public DbSet<Address> Addresses { get; set; }

最后删除数据库。

在program类修改如下:


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

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

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



    Student student1 = new Student()
    {
        Id = 2022001,
        Name = "王二小",
        Age = 19,
        Sex = "男",
        Address = Address1,
        Hobby = "打篮球",


    };

    Student student2 = new Student()
    {
        Id = 2022002,
        Name = "张小五",
        Age = 20,
        Sex = "男",
        Address = Address2,
        Hobby = "打乒乓球",

    };

    Student student3 = new Student()
    {
        Id = 2022003,
        Name = "刘小花",
        Age = 20,
        Sex = "女",
        Address = Address3,
        Hobby = "弹钢琴",


    };

    dbContext.People.AddRange(student1, student2, student3);

    Teacher teacher1 = new Teacher() { Id = 10001, Name = "张教授", Title = "教授", Sex = "男", Age = 50, Address = Address1 };
    Teacher teacher2 = new Teacher() { Id = 10002, Name = "王讲师", Title = "讲师", Sex = "男", Age = 48, Address = Address3 };

    dbContext.People.AddRange(teacher1, teacher2);
    dbContext.SaveChanges();

运行代码后,查看数据库如下:
在这里插入图片描述
我们发现这个时候没有了Discriminator 而是我们自己定义的person_type,类型也不再是string类型,是我们定义区分的1,2数值类型。

2.2 继承相同,不同表区分

但是希望映射数据库时,不同的类型映射不同的表,使用 HasBaseType((Type)null) 从层次结构中删除实体类型。删除数据库,修改DbContext类如下

 public class EFLearnDbContext:DbContext
    {
        public EFLearnDbContext()
        {
            this.Database.EnsureCreated();
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql("server=172.10.10.85;database=EFCoreLearn8;user=root;password=um-robotics", Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.28-mysql"));
         
            optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            #region Student基本配置
            modelBuilder.Entity<Student>(entity =>
            {
                entity.HasBaseType((Type)null).HasKey(x => x.Id);
                entity.Property(x => x.Id).ValueGeneratedOnAdd();//设置Id自增
                entity.Property(x => x.Name).HasMaxLength(50).IsUnicode().IsRequired();//设置姓名最大长度为50,字符为unicode,不能                              
                entity.Property(x => x.Sex).HasMaxLength(5).IsUnicode().IsRequired();//设置性别最大长度为5 字符为Unicode,不能为空                                                                   
            });
            modelBuilder.Entity<Teacher>(entity =>
            {
                entity.HasBaseType((Type)null).HasKey(x => x.Id);
                entity.Property(x => x.Id).ValueGeneratedOnAdd();//设置Id自增
                entity.Property(x => x.Name).HasMaxLength(50).IsUnicode().IsRequired();//设置姓名最大长度为50,字符为unicode                                  
                entity.Property(x => x.Sex).HasMaxLength(5).IsUnicode().IsRequired();//设置性别最大长度为5 字符为Unicode
            });
            #endregion

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

        public DbSet<Student> Students { get; set; } 
        public DbSet<Teacher> Teachers { get; set; }
        public DbSet<Address> Addresses { get; set; }
    }

在Program里修改数据如下:

    dbContext.Students.AddRange(student1, student2, student3);
    Teacher teacher1 = new Teacher() { Id = 10001, Name = "张教授", Title = "教授", Sex = "男", Age = 50, Address = Address1 };
    Teacher teacher2 = new Teacher() { Id = 10002, Name = "王讲师", Title = "讲师", Sex = "男", Age = 48, Address = Address3 };
    dbContext.Teachers.AddRange(teacher1, teacher2);
    dbContext.SaveChanges();

打开数据库查看
在这里插入图片描述

3.级联操作

这里的级联操作主要指级联删除,级联操作主要是指子实体与父实体的关系已断开时自动删除该子实体,这通常称为“删除孤立项”。
EF Core 实现多种不同的删除行为,并允许配置各个关系的删除行为。 EF Core 还实现基于关系的需求为每个关系自动配置有用的默认删除行为的约定。
EFCore的删除行为在 DeleteBehavior 枚举器类型中定义,并且可以传递到 OnDelete Fluent API 来控制是主体/父实体的删除还是依赖实体/子实体关系的断开会对依赖实体/子实体产生副作用。删除主体/父实体或断开与子实体的关系时有三个 EF 可执行的操作:

  1. 可以删除子项/依赖项
  2. 子项的外键值可以设置为 null
  3. 子项保持不变
    可选关系
    对于可选关系(可以为 null 的外键),可以保存 null 外键值,从而产生以下影响:
行为名称对内存中的依赖项/子项的影响对数据库中依赖项/子项的影响
Cascade删除实体删除实体
ClientSetNull(默认)外键属性设置为nullNone
SetNull外键属性为null外键属性设置为null
RestrictNoneNone

必选关系
对于必选关系(不可为 null 的外键),_不可以_保存 null 外键值,从而产生以下影响:

行为名称对内存中的依赖项/子项的影响对数据库中依赖项/子项的影响
Cascade删除实体删除实体
ClientSetNull(默认)SaveChanges引发异常None
SetNull引发SaveChanges异常引发SaveChanges异常
RestrictNoneNone

在上表中,“无” 可能会造成约束冲突。 例如,如果已删除主体/子实体,但不执行任何操作来更改依赖项/子项的外键,则由于发生外键约束冲突,数据库将可能会引发 SaveChanges。
注意:

  • 如果实体在没有父项时不能存在,且希望 EF 负责自动删除子项,则使用“Cascade” ,在没有父项时不能存在的实体通常使用必选关系,其中“Cascade” 是默认值。
  • 如果实体可能有或可能没有父项,且希望 EF 负责为你将外键变为 null,则使用“ClientSetNull”
  • 在没有父项时可以存在的实体通常使用可选关系,其中“ClientSetNull” 是默认值。 如果希望数据库即使在未加载子实体时也尝试将
    null 值传播到子外键,则使用“SetNull” 但是,请注意,数据库必须支持此操作,并且如此配置数据库可能会导致其他限制,实际上这通常会使此选项不适用。 这就是SetNull不是默认值的原因。
  • 如果不希望 EF Core 始终自动删除实体或自动将外键变为 null,则使用“Restrict” 。
    请注意,这要求使用代码手动同步子实体及其外键值,否则将引发约束异常

恢复前面的选项,可以看到外键约束默认都是级联的。
在这里插入图片描述

EFCore 从入门到精通-7(高级查询)

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ASP.NET Core MVC是一种用于构建Web应用程序的开发框架,具有轻量级、高扩展性和性能优越等特点。下面我将简要介绍ASP.NET Core MVC的入门到精通过程。 入门阶段:首先,你需要掌握C#编程语言和基本的Web开发知识。然后,你可以开始学习ASP.NET Core MVC的基本概念,包括请求-响应模型、控制器、视图和模型等。通过创建简单的应用程序,你可以了解到ASP.NET Core MVC的基本工作原理和项目结构。 进阶阶段:在掌握了基本概念后,你可以深入学习路由、过滤器、身份验证和授权等高级特性。此外,了解如何使用数据库和ORM(对象关系映射)框架与数据进行交互也十分重要。在这个阶段,你可以尝试开发更复杂的应用程序,并学习如何优化性能和处理错误。 精通阶段:在掌握了ASP.NET Core MVC的核心概念和高级特性后,你可以进一步提升你的技能。你可以学习如何使用视图组件、自定义标签帮助器和间件等扩展ASP.NET Core MVC的能力。此外,学习如何进行单元测试和集成测试,以及如何使用日志记录和性能监控工具等也是非常有价值的。 总结起来,要将ASP.NET Core MVC从入门到精通,你需要通过实践来不断巩固你的知识,并深入研究不同的方面和扩展。除此之外,参与开发社区和读一些相关的技术书籍也是提高你的技能和认识的好途径。希望这些信息对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值