EFCore:DBContext的基本配置
1、概述与OnConfiguring、OnModelCreating方法
除非你的数据库已经存在,否则不推荐使用反向工程来通过数据库创建模型,一般推荐使用CodeFirst模式,即代码先行的原则。在DBContext类中,最重要,也是我们最常用的两个方法就是:"OnConfiguring"和 “OnModelCreating”。参考文章: Entity Framework Code初体验
1.1 OnConfiguring
此方法可以自己进行数据库的配置,以及其他选项的配置。其中主要有以下常用的配置:配置连接字符串、配置输出的Logger、配置过滤和拦截操作、禁用和启用并发等;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseMySql("server=b.lifeiai.com;user id=EFStudent;password=lf123456;database=efstudent", Microsoft.EntityFrameworkCore.ServerVersion.Parse("5.6.50-mysql"));//连接字符串 optionsBuilder.LogTo(Console.WriteLine);//日志输出到控制台 optionsBuilder.AddInterceptors(new SoftDeleteInterception()); //添加拦截器软删除 optionsBuilder.EnableThreadSafetyChecks(false);//关闭并安全检测 } }
1.2 OnModelCreating
可以对实体类也可以说是数据表进行模型配置。模型配置主要分为两种方法:FluentAPI、数据注解
1.2.1在OnModelCreating里使用的是fluentAPI
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.UseCollation("utf8_general_ci") .HasCharSet("utf8"); modelBuilder.Entity<Student>(entity => { entity.Property(e => e.Class).HasMaxLength(50); entity.Property(e => e.Name).HasMaxLength(50); }); }
1.2.2 采用FluentAPI配置实体类有两种方式:
一、通过上面介绍的在OnModelCreating里进行配置。
二、创建实现了IEntityTypeconfiguration接口的实体类,然后再在OnModelCreating方法里添加如下方法:
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly)
示例:
<1>新建一个实体类Student
public class Student { public long Id { get; set; } public string Name { get; set; } public string Class { get; set; } public int Age { get; set; } public string Sex { get; set; } }
<2>新建一个学生配置类:
public class StudentConfig : IEntityTypeConfiguration<Student> { public void Configure(EntityTypeBuilder<Student> builder) { //设置主键 builder.HasKey(x => x.Id); //设置Id自增 builder.Property(x => x.Id).ValueGeneratedOnAdd(); //设置姓名最大长度为50,字符为unicode,不能为空 builder.Property(x=>x.Name).HasMaxLength(50).IsUnicode().IsRequired(); //设置班级最大长度为50,字符为unicode,不能为空 builder.Property(x=>x.Class).HasMaxLength(50).IsUnicode().IsRequired(); //设置性别最大长度为5 字符为Unicode,不能为空 builder.Property(x=>x.Sex).HasMaxLength(5).IsUnicode().IsRequired(); } }
<3>在EFLearnDbContext中的OnModelCreating里添加下面的代码
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); }
也可直接按如下代码配置
protected override void OnModelCreating(ModelBuilder modelBuilder) { //设置主键,并自增 modelBuilder.Entity<Student>().HasKey(x=>x.Id); modelBuilder.Entity<Student>().Property(x => x.Id).ValueGeneratedOnAdd(); //设置姓名最大长度为50,字符为unicode,不能为空 modelBuilder.Entity<Student>().Property(x => x.Name).HasMaxLength(50).IsUnicode().IsRequired(); //设置班级最大长度为50,字符为unicode,不能为空 modelBuilder.Entity<Student>().Property(x => x.Class).HasMaxLength(50).IsUnicode().IsRequired(); //设置性别最大长度为5 字符为Unicode,不能为空 modelBuilder.Entity<Student>().Property(x => x.Sex).HasMaxLength(5).IsUnicode().IsRequired(); }
1.2.3 其他方式(数据注解)
除了上述方法,还可以直接在类上配置,例如:
public class Student { [Key] //主键 public long Id { get; set; } [MaxLength(50)] //最大长度为50 [Unicode] //字符 [Required] //不能为空 public string Name { get; set; } [MaxLength(50)] //最大长度为50 [Unicode] //字符 [Required] //不能为空 public string Class { get; set; } }
数据注解的方式 优点:简单方便;缺点:耦合性太高;
FluentAPI 优点:解耦; 缺点: 编写复杂
2.Fluent API配置模型
2.1表和列的配置
EFCore默认采用和类一样的名称创建表名字,按照类的属性名称创建表中列的名称,如果需要不同的名称,可以采用下面的方法:
//NewStudent 对应着 Student表 //注解方法 [Table("Student")] public class NewStudent //FluentAPI方法 modelBuilder.Entity<NewStudent>().ToTable("Student"); //IsFemale 对应着 Gender 列 //注解方法 [Column("Gender")] public bool IsFemale { get; set; } //FluentAPI方法 modelBuilder.Entity<NewStudent>().Property(s => s.IsFemale).HasColumnName("Gender"); //列注释信息 //注解方法 [Comment("学生学号")] public string Id{ get; set; } //FluentAPI modelBuilder.Entity<Student>().Property(b => b.Id) .HasComment("学生学号"); //列类型,注解方法 [Column(TypeName = "varchar(200)")] modelBuilder.Entity<Student>().Property(b => b.Name) .HasColumnType("varchar(200)")
默认情况下,在使用迁移创建表时,EF Core 首先为主键列排序,然后为实体类型和从属类型的属性排序,最后为基类型中的属性排序,也可如下指定排序:
//注解方法 [Column(Order = 0)] public int Id { get; set; } [Column(Order = 1)] public int Name{ get; set; } //FluentAPI modelBuilder.Entity<Employee>(x => { x.Property(b => b.Id) .HasColumnOrder(0); x.Property(b => b.Name) .HasColumnOrder(1); });
2.2 约束性配置
最大长度 字符串或者数组类型最大的长度
//最大长度 字符串或者数组类型最大的长度 //注解方法 / FluentAPI [MaxLength(500)] / HasMaxLength(500); //精度和小数位数 [Precision(14, 2)]/HasPrecision(14, 2) //Unicode 和非 Unicode 文本数据 [Unicode(false)]/IsUnicode(false) //必需和可选属性 [Required]/IsRequired() //忽略,标记模型某个属性可以使该属性不必映射到数据库。 [NotMapped]/.Ignore()
2.3 键的配置
在EFCore约定中没有显示的指定键,那么默认名为 类名+Id结尾 的属性将被配置为实体的主键。
//注解方法 / FluentAPI [Key]/HasKey(c => c.Id)
组合键(多个属性配置为实体的键),只能使用 Fluent API 进行配置:
modelBuilder.Entity<Student>().HasKey(c => new { c.Id, c.Nmae});
2.4自增和默认设置
//注解方法 / FluentAPI //自增 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] / ValueGeneratedOnAdd(); //默认值 HasDefaultValue(3); / .HasDefaultValueSql("getdate()");
2.5 关系配置
描述实体类型(表)之间的关系,大部分只能用FluentAPI,如下:
.HasOne(b => b.BlogImage).WithOne(i => i.Blog);//一对一 .HasOne(p => p.Blog).WithMany(b => b.Posts); //一对多 .HasMany(p => p.Tags).WithMany(p => p.Posts);//多对多
2.6 索引
//注解方法 / FluentAPI //单一索引 [Index(nameof(Url))] / HasIndex(b => b.Url); //复合索引 [Index(nameof(FirstName), nameof(LastName))] / .HasIndex(p => new { p.FirstName, p.LastName }); //唯一索引 [Index(nameof(Url), IsUnique = true)] / .HasIndex(b => b.Url).IsUnique();
还以一些不是太常用的配置,可以参考微软的官方文档查看。LINK