最近终于闲下来了,有点时间来写一下使用efcore过程中遇到的的一些细节问题。这个系列会从基础开始,可能会比较啰嗦(~ ̄▽ ̄)~。
开发环境 VS2019 .NET Core2.2 mysql8.0
会用到的包,列一下:
Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Tools Pomelo.EntityFrameworkCore.MySql Microsoft.Extensions.Configuration Microsoft.Extensions.Configuration.Json
为什么不用官方的包MySql.Data.EntityFrameworkCore,我只能说,从2018年4月份开始使用corefirst的体验来看,官方的驱动做的实在是烂,对数据迁移不够友好,至2019年群里的小伙伴还在吐槽不支持GUID(未核实)。
接下来是正文:
文章目录
1. 新建一个控制台项目EFCoreFirst,做一下简单的演示就不用web项目了。
添加一个appsetting.json配置文件,属性设置始终复制
{ "ConnectionString": "server=127.0.0.1;port=3306;database=efcore_demo;uid=sa;pwd=123456;" }
2. 安装包

3. 添加实体
ef core是关于访问数据库的,但是这个数据库是从哪里来的呢?ef core提供了两个选项:通过ef core创建它,称为code first,或者手动创建数据库,称为database first。
这个例子中会使用codefirst创建一个简单的数据库,包含两张表:Products 包含产品信息,Order 包含订单信息

现在可以开始编写efcore相关的代码了,在创建任何数据库访问代码之前,需要编写两个基本部分:
3.1 由ef core映射到数据库中表的类
3.2 应用程序的DbContext,用于配置和访问数据库的类
products类:
[Table("product")] public class Products { /// <summary> /// key显示将ProductId设为主键,但是我们已经使用了efcore命名约定,它告诉efcore属性ProductId是主键,所以可以省略 /// </summary> [Key] public virtual int ProductId { get; set; } /// <summary> /// 产品名称 /// </summary> [StringLength(50)] public virtual string Name { get; set; } /// <summary> /// 产品数量 /// </summary> public virtual int Count { get; set; } /// <summary> /// 价格 /// </summary> public virtual Decimal Price { get; set; } /// <summary> /// 外键 /// </summary> public virtual int OrderId { get; set; } /// <summary> /// Order属性是efcore导航属性。efcore在save中使用这个来查看products否附加了order类,如果附加了order类,它将设置外键orderId /// 这里有一个新的命名约定 efcore知道OrderId是一个外键,当它与Order类的主键名称一致 /// </summary> public virtual Order Order { get; set; } }
Order类:
[Table("order")] public class Order { [Key] public virtual int OrderId { get; set; } /// <summary> /// 订单编号 /// </summary> [StringLength(25)] public virtual string OrderCode { get; set; } /// <summary> /// 买家名称 /// </summary> [StringLength(25)] public virtual string Buyer { get; set; } }
4. 添加数据库上下文
public class AppDbContext:DbContext { private static string ConnStr; static AppDbContext() { var builder = new ConfigurationBuilder(); builder.AddJsonFile("appsetting.json"); var config = builder.Build(); ConnStr = config["ConnectionString"]; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseMySql(ConnStr); } public DbSet<Products> Products { get; set; } }
5. 添加迁移文件,执行迁移

查看生成的数据库表,可以看到表product表按预期生成

efcore生成迁移文件的过程,以products为例子:
5.1 在AppDbContext中查找所有DbSet<T> 属性,这里找到了Products类,获取到了表名称(从Table特性中,未设置则默认为类名)
5.2 查看DbSet<T>中所有类T(这里是Products类),并查看其属性以计算列名、类型等。它还查找类和或属性上提供额外建模信息的特殊属性如StringLength特性
5.3 查找DbSet<T>类所引用的任何类(Products类中的Order)。在这个例子中,Products类引用了Order类,所以efcore也会扫描它。它对Order类的属性执行与步骤2中对Products相同的操作。
5.4 efcore在应用程序的DbContext中运行OnModelCreating方法,这里我们未重写这个方法,该方法可以添加一些配置。
5.5 efcore根据以上步骤收集的所有信息创建数据库的内部模型,生成迁移文件。
6. 尝试操作数据
public class Program { static void Main(string[] args) { AddProduct(); var product = GetSingleProduct(); Console.WriteLine($"{product?.ProductId}--{product?.Name}"); Console.ReadLine(); } public static void AddProduct() { using (var dbContext=new AppDbContext()) { var product = new Products() { Name = "apple", Price = 3.0M, Count = 10, Order = new Order { OrderCode = "0001", Buyer="xiaoming" } }; dbContext.Add<Products>(product); dbContext.SaveChanges(); } } public static Products GetSingleProduct() { using (var dbContext = new AppDbContext()) { var product = dbContext.Products.FirstOrDefault(); return product; } } }
操作成功:
