EF CORE学习笔记(一) 配置Dbcontext
从Nuget下载数据库依赖
数据库对应的依赖包:
贴几个常用数据库
-
SqlServer:Microsoft.EntityFrameworkCore.SqlServer (支持 SqlServer 2005 +)
-
Sqlite:Microsoft.EntityFrameworkCore.Sqlite
-
MySql:
-
MySql.EntityFrameworkCore:支持 (MySql 8.x +)
-
Pomelo.EntityFrameworkCore.MySql:(支持 MySql 5.x +)
-
配置Dbcontext
自己新建一个类继承Dbcontext类(需引入命名空间 Microsoft.EntityFrameworkCore
)
此类必须具有DbContextOptions<ApplicationDbContext>
参数的公共构造函数 例如:
public class defaultDbcontext : DbContext
{
public defaultDbcontext(DbContextOptions<defaultDbcontext> options):base(options)
{
}
}
配置连接字符串
所有 DbContext
配置的起始点都是 DbContextOptionsBuilder
可以通过三种方式获取此生成器:
-
在 AddDbContext 和相关方法中
通过依赖注入在 Startup 类中的 ConfigureServices方法中 使用 AddDbContext 方法配置
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<defaultDbcontext>(optin=> { optin.UseSqlite("data source=./blog.db"); }); }
-
在 OnConfiguring 中
重写继承类的
OnConfiguring
方法public class defaultDbcontext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.optin.UseSqlite("data source=./blog.db"); } }
这些
Use*
" 方法是由数据库提供程序实现的扩展方法。 这意味着必须先安装数据库提供程序 NuGet 包,然后才能使用扩展方法。创建并模型
我个人理解就是根据实体生成数据库并且配置数据库各个字段(只是个人理解),说一下EFcore 是如何根据实体生成模型的具体可以参考
https://blog.csdn.net/catshitone/article/details/116595167
EFcore提供了两种方式生成模型 一种是 fluent API 一种是 数据注释 也就是特性 ,接下来分别演示下两种方式配置使用 fluent API 配置模型
在我们刚刚创建的派生类
defaultDbcontext
中重写OnModelCreating
方法,代码如下protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<blog>(); //blod是实体类 还可以单独配置实体的属性 例如下面这句代码 //modelBuilder.Entity<blog>().Property(x=>x.img).IsRequired(); 就表示img不能为空 更多的配置方法稍后贴个表格。 }
使用数据注释方法(也叫特性)
public class blog { public int id { get; set; } public string titile { get; set; } public string img { get; set; } [Required] public string url { get; set; } public int Writerid { get; set; } public Writer Writer { get; set; } }
使用特性方式要在派生类
defaultDbcontext
中添加公开DbSet<Blog>
类型的属性 让EFcore 知道要根据哪个实体类生成模型。贴上完整代码public class defaultDbcontext:DbContext { public defaultDbcontext(DbContextOptions<defaultDbcontext> options):base(options) { } public DbSet<blog> blogs; } public class blog { public int id { get; set; } public string titile { get; set; } public string img { get; set; } [Required] public string url { get; set; } public int Writerid { get; set; } public Writer Writer { get; set; } }
如果一个实体使用两种方式配置 那么fluent API会替代特性方式
约定
这里贴上 官方文档的说明:
按照约定,在上下文中的 DbSet 属性中公开的类型作为实体包含在模型中。 还包括方法中指定的实体类型 OnModelCreating ,就像通过递归方式浏览其他发现的实体类型的导航属性找到的任何类型一样。
这句话什么意思呢 看官方给出的代码
internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AuditEntry>(); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public List<Post> Posts { get; set; } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public Blog Blog { get; set; } } public class AuditEntry { public int AuditEntryId { get; set; } public string Username { get; set; } public string Action { get; set; } }
在上面的代码中 因为实体Blod 在类型为
DbSet<Blog>
的属性中所以它包含在模型中
而实体Post是实体Blod的导航属性所在它包含在模型中
实体AuditEntry在OnModelCreating配置所在它包含在模型中实体的属性约定
- 默认会把名字为id的属性配置为主键,并且为自增长。
- 默认情况下属性类型可为空对应的数据库列可以为null,值类型对应的列不能为null
下面贴出常见约定
特性 | 应用范围 | 功能 | FluentAPI |
---|---|---|---|
[NotMapped] | 类或属性 | 在模型中排除此类或此属性的映射 | modelBuilder.Ignore<BlogMetadata>(); modelBuilder.Entity<Blog>().Ignore(b => b.LoadedFromDatabase); |
[Table("xxx")] | 类 | 设置这个类对应的数据库表名,默认表名是DbSet<T> 的属性名 | modelBuilder.Entity<Blog>().ToTable("blogs"); |
[Table("xxx", Schema = "blogging")] * | 类 | 用来设置映射的表架构,默认的架构是dbo | modelBuilder.Entity<Blog>().ToTable("blogs", schema: "blogging") ; |
[Column("xxx")] | 属性 | 用来设置要映射的列名 | modelBuilder.Entity<Blog>().Property(b => b.BlogId).HasColumnName("blog_id"); |
[Column(TypeName="varchar(200)")] | 属性 | 用来设置列的数据类型 默认情况下 DateTime 会映射为datetime2(7) ,string 映射到nvarchar(max) 或nvarchar(450) | modelBuilder.Entity<Blog>(eb =>{eb.Property(b => b.Url).HasColumnType("varchar(200)");eb.Property(b => b.Rating).HasColumnType("decimal(5, 2)");}); |
- | - | 映射到数据库视图 | modelBuilder.Entity<Blog>().ToView("blogsView", schema: "blogging"); |
- | - | 映射到表值函数(TVF[) | 链接 |
[Comment("xxxx")] | 类或属性 | 表或列的注释 | modelBuilder.Entity<Blog>().HasComment("xxxx"); modelBuilder.Entity<Blog>().Property(b => b.Url).HasComment("The URL of the blog"); |
[MaxLength(500)] | 属性 | 设置最大长度,适用于数组数据类型,如string 和byte[] | modelBuilder.Entity<Blog>().Property(b => b.Url).HasMaxLength(500); |
- | - | 设置精度和小数位 通常为 decimal 或DateTime 类型的属性 | modelBuilder.Entity<Blog>().Property(b => b.Score).HasPrecision(14, 2);modelBuilder.Entity<Blog>().Property(b => b.LastUpdated).HasPrecision(3); |
[Required] | 属性 | 设置列为非空 默认情况下可空类型对应的列可以为null,值类型不为null | modelBuilder.Entity<Blog>().Property(b => b.Url).IsRequired(); |
[Key] | 属性 | 设置主键 | modelBuilder.Entity<Car>().HasKey(c => c.LicensePlate); 1.这个特性没法应用到复合主键上,但是可以通过FluentAPI的方式: modelBuilder.Entity<Car>().HasKey(c => new { c.State, c.LicensePlate }); 2.设置主键名称 modelBuilder.Entity<Blog>().HasKey(b => b.BlogId).HasName("PrimaryKey_BlogId"); ,默认名称是PK_<type name> |
[Index(nameof(Url),Name="Index_Url")] ** | 类 | 给实体的Url属性对应的列上设置索引,并指定索引的名称 | modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasDatabaseName("Index_Url"); |
[Index(nameof(FirstName), nameof(LastName))] | 类 | 设置复合索引 | modelBuilder.Entity<Person>().HasIndex(p => new { p.FirstName, p.LastName }); |
[Index(nameof(Url), IsUnique = true)] | 类 | 设置唯一索引 | modelBuilder.Entity<Blog>().HasIndex(b => b.Url).IsUnique(); |
[Keyless] | 类 | 设置此实体里没有主键,框架不会对此实体的状态进行跟踪,即使有更改也不会保存到数据库中 | modelBuilder.Entity<Blog>().HasNoKey(); |
**:默认的索引名称是IX_<type name>_<property name>
最后说下迁移
迁移需要安装工具包Microsoft.EntityFrameworkCore.Tools
安装完成后在Nuget控制台运行添加迁移命令 Add-Migration init
init是迁移名称,可随意。 在运行 Update-Database init
应用迁移将所做更改应用到数据库。