• 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

  • 相关阅读:
    安卓图片载入之使用universalimageloader载入圆形圆角图片
    加密散列算法——SHA-1
    图片分类器
    LeetCode——Regular Expression Matching
    LeetCode Set Matrix Zeroes
    怎样通过浏览器分析前后端交互
    Android自己定义dialog中的EditText无法弹出键盘的解决
    @Async
    @Transactional 事务
    运行报错
  • 原文地址:https://www.cnblogs.com/zt102545/p/13940217.html
Copyright © 2020-2023  润新知