大多数人,都低估了编程学习的难度,而高估了自己的学习能力和毅力。
当前系列: 垃圾桶 修改讲义

两种方式

大部分的自定义配置都可以使用OnModelCreating()和Annotations两种方式。


OnModelCreating()

之前我们使用的都是EF的默认配置。某些情况我们可能会想要进行一些自定义的修改,这就需要在OnModelCreating()中使用方法配置:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Major>();
        }

顾名思义,OnModelCreating在Moldel创建时被EF自动调用,通过modelBuilder.Entity<T> ()就可以设置T的自定义映射细节。


包含

默认的(by convention),EF会把以下三种class映射到数据库

  1. DbContext子类中DbSet<T>属性(注意:必须是属性,字段不行)的泛型参数指定的类型
  2. OnModelCreating()中配置的Entity<T>里的泛型参数指定的类型。如上文中的Major。即使没有DbSet<Major>属性,EF仍然会将Major进行映射。
  3. 上述两种类型里被引用到的类型(后文详述)
演示:


排除

如果想要排除掉一些属性,可以使用:

    modelBuilder.Entity<Student>().Ignore(s => s.Age);

甚至可以直接ignore掉整个Entity:

    modelBuilder.Ignore<Student>();

演示:查看Migration和Database……


Data Annotations

或者,也可以在Entity和它的属性上使用
        [NotMapped]
        public string Age { get; set; }

Annotation在我们学习ASP.NET Model 验证时就被使用过。(演示:F12之后定位到System.ComponentModel.Annotations.dll

注意理解:特性本身并没有什么作用,起作用的是利用反射检索特性的框架,比如:ASP.NET和EF。


表名列名

默认EF会使用DbSet属性名(如果有的话),或类名(OnModelCreating()中引入),但是我们也可以自定义的指定表名列名

    modelBuilder.Entity<NewStudent>().ToTable("Student");

或者,

    [Table("Student")]
    public class NewStudent  //NewStudent 对应着 Student表
列名也类似:
    modelBuilder.Entity<NewStudent>().Property(s => s.IsFemale)
        .HasColumnName("Gender");

或者,

    [Column("Gender")]
    public bool IsFemale { get; set; }


数据类型

EF对各种基本数据类型的映射都比较完美,比如C#的int自动对应SQL的int,bool对应bit……


日期

注意EF会将DateTime自动映射成SQL中的DateTime2。

这是因为C#中DateTime的默认值是0001-01-01 00:00:00.0000000

  • 和SQL Sever中的DateTime2匹配,
  • 和最小值为1753-01-01 的DateTime匹配


枚举

枚举会自动转为int类型

演示:DayOfWeek Oncall


字符串

可以指定的是字符串长度(默认max)。

通过MaxLength轻松实现:

        [MaxLength(50)]
        public string Name { get; set; }
            modelBuilder.Entity<Student>(options =>
            {
                options.Property(s => s.Name).HasMaxLength(50);
            });

HasColumnType()

还可以用字符串直接指定(简单粗暴)

    modelBuilder.Entity<Student>()
        .Property(s => s.Oncall).HasColumnType("NVARCHAR(20)");


NULL Constraint

对于C#中有默认值的值类型属性(比如int),EF默认是映射为NOT NULL的;要想EF默认映射为可以NULL值,需要将其声明为可空类型,比如int?。

对于引用类型(如字符串),EF默认是映射为可以NULL,要想变成NOT NULL:

    modelBuilder.Entity<Student>()
        .Property(s => s.Name).IsRequired(); 
或者
    [Required]
    public string Name { get; set; }


CHECK约束

比如Age只能在0-150之间。你可以会认为使用Range特性即可:

    [Range(0, 150)]  //不会自动生成CHECK约束
    public int Age { get; set; }
但这是行的,需要在OnModelCreating中进行配置(EF core3.0之后版本):
    modelBuilder.Entity<Student>()
        .HasCheckConstraint("CK_Age","Age Between 0 AND 150")

演示查看生成的SQL

ALTER TABLE [dbo].[TB_Student]
    ADD CONSTRAINT [CK_Age] CHECK ([Age]>=(0) AND [Age]<=(150));

Primary Key

EF默认将Entity中的Id或者<entity>Id作为主键。如果我们要指定其他主键(不推荐,除了关系表的联合主键),可以:

            modelBuilder.Entity<Student>()
                .HasKey(s => s.Name);

或者:

        [Key]
        public string Name { get; set; }

联合主键因为要跨多列,所以只能设置在OnModelCreating()中:(后文详述)

    modelBuilder.Entity<StudentAndTeacher>()
        .HasKey(st => new { st.TeacherId, st.StudentId });


Index

除了主键,EF不会自动添加索引。

我们需要自己添加:

        modelBuilder.Entity<Student>()
            .HasIndex(s => s.Name)
            .IsUnique();   //默认是非唯一的
    modelBuilder.Entity<Student>()
        //联合键索引
        .HasIndex(s=>new {s.Name, s.Age })

或者,在Entity类上(EF Core中)

    [Index("Name", IsUnique = true)]
    public class Student


作业

分别使用OnModelCreating()和Data Annotations,完成以下配置:
  • 将之前的User类名改为Register,但仍然能对应表User
  • 将之前的User属性Name改成UserName,但仍然能对应表User的列Name
  • 将Name的长度限制为256
  • Password不能为空
  • 将User表的主键设置在Name列上
  • User类中的属性FailedTry不用存储到数据库中
  • 给CreateTime属性添加一个非聚集唯一索引
  • CreateTime不能小于2000年1月1日
学习笔记
源栈学历
今天学习不努力,明天努力找工作

作业

觉得很 ,不要忘记分享哟!

任何问题,都可以直接加 QQ群:273534701

在当前系列 垃圾桶 中继续学习:

上一课: 【废】EF core:

多快好省!前端后端,线上线下,名师精讲

  • 先学习,后付费;
  • 不满意,不要钱。
  • 编程培训班,我就选源栈

更多了解 加:

QQ群:273534701

答疑解惑,远程debug……

B站 源栈-小九 的直播间

写代码要保持微笑 (๑•̀ㅂ•́)و✧

公众号:源栈一起帮

二维码