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

