EF Core实体类配置
EF Core实体类配置
约定大于配置
主要的约定规则
规则1:数据库表名采用上下文类中对应的DbSet的属性名。
规则2:数据库表列的名字采用实体类属性的名字,列的数据库类型采用和实体类属性类型兼容的类型。比如在SQL Server中,string类型对应nvarchar,long类型对应bigint.
规则3:数据库表列尔可空性取决于对应实体类熟悉的可空性。
规则4:名字为Id的属性为主键,如果主键为short、int或者long类型,则主键默认采用自动增长类型的列。
Data Annotation(数据注解)
Data Annotation指的是可以使用.NET提供的Attribute对实体类、属性等进行标注的方式来实现实体类配置。比如通过[Table(“T_Books”)],我们可以把实体类对应的表名配置为T_Books;
1 | //指定表名 |
优点:简单 | 缺点:耦合
Fluent API
Fluent API属于官方的推荐用法
Fluent API能够更好地进行职责分离。实体类只能负责进行抽象地描述,不涉及与数据库相关的细节,所有和数据库相关的细节被放到配置类中,这样我们能更方便地进行大型项目的管理。
2.Fluent API的功能更强大。Fluent API几乎能实现Data Annotation的所有功能,而Data Annotation则不支持Fluent API的一些功能。
Fluent API 基本配置
视图与实体类映射
可以用下面的代码把blogsView这个数据库中的视图和Blog实体类进行映射:
1 | modelBuilder.Entity<Blog>().ToView("blogView"); |
排除属性映射
一个实体类的所有属性都会映射到数据库表中,如果想让EF Core忽略一个属性,就可以用lgnore配置。
1 | modelBuilder.Entity<Blog>().Ignore(b=>b.Name2); |
数据库表列名
数据库表中的列名默认和属性名一样,我们可以使用HasColumnName方法配置一个不同的列名。
1 | modelBuilder.Entity<Blog>().Property(b=>b.BlogId).HasColumnName("blog_id"); |
列数据类型
EF Core默认会根据实体类的属性类型、最大长度等确定字段的数据类型,我们可以使用HasColumnType为列指定数据类型。
1 | builder.Property(e=>e.Tilte).HasColumnType("nvarchar(200)"); |
主键
EF Core默认把名字为Id或者“实体类型+id”的属性作为主键,我们可以用HasKey配置其他属性作为主键。
1 | modelBuilder.Entity<Student>().HasKey(c=>c.Number); |
索引
EF Core中可用HasIdex方法配置索引。
1 | modelBuilder.Entity<Blog>().HasIndex(b=>b.Url); |
EF Core也支持多个属性组成的复合索引,只要给HasIndex方法传递由一个或多个属性的名字组成的匿名类对象即可。
1 | modelBuilder.Entity<Person>().HasIndex(p=>new{p.FirstName,p.LastName}); |
EF Core中定义的索引不是唯一索引,我们可以用IsUnique方法把索引配置为唯一索引。我们还可以用IsClustered方法把索引设置为聚集索引。
主键类型选择并不简单
在数据库设计中,对于主键类型来讲,有自动自增(简称自增)的long类型和Guid类型两种常用的方案。
普通自增
自增long类型的使用非常简单,所有主流数据库系统都内置了对自增列的支持,新插入的数据库会由数据库自动赋予一个新增的、不重复的主键值。自增long类型占用磁盘空间小,可读性强,但是自增long类型的主键在数据库迁移以及分布式系统(分布表、数据库集群)中使用起来比较麻烦,而且在高并发插入的时候性能比较差。
由于自增列的值一般都是由数据库生成的,因此无法提前获得新增数据行的主键值,我们需要把数据保存到数据库之后才能获得主键的值。
1 | Dog dog=new Dog(); |
Guid算法
Guid算法使用网卡的MAC地址,时间戳等信息生成一个全球唯一的ID。由于Guid的全球唯一性,它适用于分布式系统,在进行多数据库数据合并的时候很方便,因此我们也可以用Guid类型作为主键。
值得注意的是,由于Guid算法生成的值是不连续的,(即使是SQLServer中NewSequentialId函数生成的Guid也不能根本解决这个问题),因此我们在使用Guid类型作为主键的时候,他将会导致新插入的每条数据都要经历查找何时插入位置的过程,在数据量大的时候将会导致非常糟糕的数据插入性能。
1 | Rebbit r = new Rebbit(); |
其他数据库迁移命令
Update-database 其他参数
可以用Update-database XXX 把数据库回滚到XXX迁移脚本之后的状态。注意,这个命令只能把当前连接的数据库进行回滚,因此迁移脚本仍然存在。
删除迁移脚本
可以用Remove-migration命令删除最后一次的迁移脚本。
生产迁移脚本
EF Core中提供了Script-Migration命令来根据迁移代码生成SQL脚本,在【程序包管理器控制台】中输入Script-Migration并执行,一个包含完整的数据库操作脚本的SQL文件就会被创建和打开。
如果生产数据库已经处于某个迁移版本的状态,那么我们可以生成这个版本D到版本F的SQL脚本:Script-Migration D F。
还可以使用context.Database.Migrate()代码来对程序当前连接的数据库进行迁移。这种方式是直接在代码中完成数据库迁移,很多公司的安全审计要求提供的是明文的SQL语句。
查询EF Core生成的SQL语句
使用简单日志查看SQL语句
只要在上下文的OnConfiguring方法中调用optionsBuilder类的LogTo方法,查询SQL语句,输出到控制台。
1 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) |
记录到文件
1 | private readonly StreamWriter _logStream = new StreamWriter("mylog.txt", append: true); |