EFCore CodeFirst操作MySQL
安装包
新建项目,选择NETCore2.2版本
打开NuGet,搜索安装以下几个包
- Microsoft.EntityFrameworkCore 2.2.6版本
- MySql.Data 8.0.19版本
- MySql.Data.EntityFrameworkCore 8.0.19版本
- MySql.Data.EntityFrameworkCore.Design 8.0.19版本
创建DBContext
新建DataDBContext,继承DbContext
using EFCore.Model;
using Microsoft.EntityFrameworkCore;
namespace EFCore.DAL
{
public class DataDBContext : DbContext
{
public DataDBContext(DbContextOptions<DataDBContext> options) : base(options)
{
}
}
}
appsetting.json文件中加入mysql连接字符串
"ConnectionSetting": {
"MySqlConnection": "Data Source=localhost;User ID=root;Password=123456;Database=EFDemo;Allow User Variables=True;Charset=utf8;"
}
在StartUp.cs中注入DataDBContext
//ConfigureServices方法中注入DbContext
services.AddDbContext<DataDBContext>(options => options.UseMySQL(Configuration["ConnectionSetting:MySqlConnection"]));
Configure方法添加参数context,自动创建数据库。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, DataDBContext context)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
context.Database.EnsureCreated();//数据库不存在的话,会自动创建
}
编译运行一下,数据库自动创建了,但是还没有表。
关联表
新建4个model类做示例,演示一对一,一对多,多对多关系。
Province类:省份信息,跟城市是一对多关系
using System.Collections.Generic;
namespace EFCore.Model
{
public class Province
{
public Province()
{
Cities = new List<City>();
}
public int ID { get; set; }
public string name { get; set; }
public int population { get; set; }
public List<City> Cities { get; set; }
}
}
City类:城市信息,跟省份是多对一关系,更公司是多对多关系。
注意CityCompanies 必须为属性,否则关联后在迁移的时候会报错:
he expression ‘x => x.CityCompanies’ is not a valid property expression. The expression should represent a simple property access: ‘t => t.MyProperty’.
Parameter name: propertyAccessExpression
using System.Collections.Generic;
namespace EFCore.Model
{
public class City
{
public City()
{
CityCompanies = new List<CityCompany>();
}
public int ID { get; set; }
public string name { get; set; }
public string areaCode { get; set; }
public int ProvinceID { get; set; }
public Province Province { get; set; }
public List<CityCompany> CityCompanies { get; set; }
public Mayor Mayor { get; set; }
}
}
Company类:公司信息,跟城市是多对多关系。CityCompanies 一样必须为属性。
using System;
using System.Collections.Generic;
namespace EFCore.Model
{
public class Company
{
public Company()
{
CityCompanies = new List<CityCompany>();
}
public int ID { get; set; }
public string Name { get; set; }
public DateTime CreateTime { get; set; }
public string LegalPerson { get; set; }
public List<CityCompany> CityCompanies { get; set; }
}
}
CityCompany类:关联城市和公司的表,CityID和CompanyID关联作为主键
namespace EFCore.Model
{
public class CityCompany
{
public int CityID { get; set; }
public City City { get; set; }
public int CompanyID { get; set; }
public Company Company { get; set; }
}
}
Mayor类:市长信息,跟城市是一对一关系。
namespace EFCore.Model
{
public class Mayor
{
public int ID { get; set; }
public string name { get; set; }
public int sex { get; set; }
public int CityID { get; set; }
public City City { get; set; }
}
}
DataDBContext类里重写OnModelCreating方法,建立表的关联关系。
using EFCore.Model;
using Microsoft.EntityFrameworkCore;
namespace EFCore.DAL
{
public class DataDBContext : DbContext
{
public DataDBContext(DbContextOptions<DataDBContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//关联表,指定两个ID为主键。
modelBuilder.Entity<CityCompany>().HasKey(x => new { x.CityID, x.CompanyID });
//关联一对多关系,一个省份多个城市
modelBuilder.Entity<City>().HasOne(x => x.Province).WithMany(x => x.Cities).HasForeignKey(x => x.ProvinceID);
//关联多对多关系,一个城市多个公司
modelBuilder.Entity<CityCompany>().HasOne(x => x.City).WithMany(x => x.CityCompanies).HasForeignKey(x => x.CityID);
//关联多对多关系,一个公司多个城市
modelBuilder.Entity<CityCompany>().HasOne(x => x.Company).WithMany(x => x.CityCompanies).HasForeignKey(x => x.CompanyID);
//关联一对一关系,一个城市一个市长
modelBuilder.Entity<Mayor>().HasOne(x => x.City).WithOne(x => x.Mayor).HasForeignKey<Mayor>(x => x.CityID);
}
//省份
public DbSet<Province> Provinces { get; set; }
//城市
public DbSet<City> Cities { get; set; }
//公司
public DbSet<Company> Companies { get; set; }
//城市公司关联表
public DbSet<CityCompany> CityCompanies { get; set; }
//市长
public DbSet<Mayor> Mayors { get; set; }
}
}
迁移数据库
打开NuGet程序包管理器控制台执行以下指令:
##用于查看EF的常用指令
get-help EntityFrameworkCore
可以看到EF下的这些指令说明
执行Add-Migration用于创建迁移数据,迁移文件名自己定,名称唯一的,每次修改数据库都需要重新命名个迁移名称。这里命名为“EFMySQL”,执行时需要把项目设为启动项。
Add-Migration EFMySQL
创建完成后可以看到项目栏里多了个Migration文件夹,就是刚刚创建的迁移。
执行Update-Database开始迁移数据
Update-Database
首次进行迁移执行update-database的时候,有可能会报以下错:
MySql.Data.MySqlClient.MySqlException (0x80004005): Table '__efmigrationshistory' doesn't exit
解决方式是:
去mysql里手动创建这个 ‘__efmigrationshistory’ 表,这个表示执行操作的记录,因为可能对表增加字段,修改字段,删除字段等等;
CREATE TABLE `__EFMigrationsHistory`
(
`MigrationId` nvarchar(150) NOT NULL,
`ProductVersion` nvarchar(32) NOT NULL,
PRIMARY KEY(`MigrationId`)
);
然后执行update-database,这样数据迁移就能完成了,表现表已经创建好了。
PS:
想要删除迁移数据,可以执行以下指令。
##删除表结构
Update-Database -Migration:0
##删除迁移文件
Remove-Migration
种子数据
DataDBContext类里之前重写OnModelCreating方法里添加以下代码。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Province>().HasData(
//需要指定ID,如果是GUID,请写死,不要new GUID()
new Province { ID = 1, name = "广东", population = 9000_000 },
new Province { ID = 2, name = "福建", population = 8000_000 }
);
modelBuilder.Entity<City>().HasData(
//需要指定外键ProvinceID
new City { ProvinceID = 1, ID = 1, name = "汕头" },
new City { ProvinceID = 1, ID = 2, name = "广州" },
new City { ProvinceID = 1, ID = 3, name = "深圳" }
);
}
然后再执行数据迁移指令
Add-Migration xxx
Update-Database
可以看到数据已经添加进来了
增删改查
SaveChanges():内部通过事务来执行,如果一条SQL语句执行失败,执行回滚操作;
内部执行步骤:
- 检查所有正在追踪的对象
- 读取每个对象的状态
- 生成SQL语句
- 执行所有生成的SQL语句
- 如果有返回数据的话,就获取这些返回数据。
新增
单一新增
Province province = new Province
{
//int类型的ID默认为主键自增,所以不需要添加。
name="北京",
population=200000
};
//_context追踪对象
_context.Provinces.Add(province);//或这种写法也可以:_context.Add(province);
//执行SQL语句,执行成功后返回ID到province对象里。
_context.SaveChanges();
批量新增
批量操作是有大小限制的。默认大小限制是由数据库Provider定的,如果超出该大小,那么超出部分将会由另外批次来处理。
Province province = new Province
{
//int类型的ID默认为主键自增,所以不需要添加。
name="北京",
population=200000
};
Company company = new Company
{
Name = "腾讯",
CreateTime = new DateTime(),
LegalPerson = "小马哥"
};
_context.AddRange(province, company);
_context.SaveChanges();
查询
查询主要通过LinQ来添加过滤条件。
var province = _context.Provinces.Where(x => x.name == "北京").ToList();//执行到ToList()的时候才会去查询,其他LinQ方法也一样。
修改
追踪对象的修改
var province = _context.Provinces.FirstOrDefault();
if (province != null)
{
province.population += 100;
_context.Provinces.Add(new Province
{
name = "上海",
population = 200000
});
_context.SaveChanges();
}
修改非追踪对象
var province = _context.Provinces.FirstOrDefault();
if (province != null)
{
province.population += 100;
_context.Provinces.Add(new Province
{
name = "上海",
population = 200000
});
_context2.Update(province);//这里的_context2是另一个DataDBContext示例,所有没有追踪province对象,所以需要用Update()来追踪对象。
_context2.SaveChanges();
}
删除
删除需要把对象先查出来再执行删除
var province = _context.Provinces.FirstOrDefault();
_context.Remove(province);
_context.SaveChanges();
原生SQL
详情查看官网地址吧:
https://docs.microsoft.com/zh-cn/ef/core/querying/raw-sql