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

原文地址:https://www.cnblogs.com/zt102545/p/13940217.html