003 Entity Framework Core 2.x P3 插入数据和简单查询

003 Entity Framework Core 2.x P3 插入数据和简单查询


博客园文章Id:12709575


在Asp .Net Core项目中使用Entity Freamwork Core

项目架构

项目架构
项目架构

AspEFCore.Data

依赖项

Microsort.EntityFrameworkCore.Tools 迁移命令

Microsoft.EntityFrameworkCore.Design迁移引擎

Microsoft.Extensions.Logging.Debug 与Debug相关的日期记录
Microsoft.Extensions.Logging.Console 将日志输出到控制台的扩展

引用项目

AspEFCore.Domain.Models

AspEFCore.Domain.Models

依赖项

Microsoft.EntityFrameworkCore 与Debug相关的日期记录
Microsoft.EntityFrameworkCore.SqlServer 将日志输出到控制台的扩展

AspEFCore.Web

依赖项

Microsort.EntityFrameworkCore.Tools 迁移命令

创建以下实体类模型

using System.Collections.Generic;

namespace AspEFCore.DoMain.Models
{
    public class City
    {
        /// <summary>
        /// 主键Id
        /// </summary>
        public int CityId { get; set; }

        /// <summary>
        /// 外键Id
        /// </summary>
        public int ProvinceId { get; set; }

        /// <summary>
        /// 导航属性
        /// </summary>
        public Province Province { get; set; }

        public IEnumerable<CityCompany> CityCompanies { get; set; }
        public Mayor Mayor { get; set; }
    }
}
namespace AspEFCore.DoMain.Models
{
    public class CityCompany
    {
       public int CityCompanyId { get; set; }

        public int CityId { get; set; }
        public City City { get; set; }

        public int CompanyId { get; set; }
        public Company Company { get; set; }
    }
}
using System;
using System.Collections.Generic;

namespace AspEFCore.DoMain.Models
{
    public class Company
    {
        public Company()
        {
            CityCompanies = new List<CityCompany>();
        }

        public int CompanyId { get; set; }

        public string Name { get; set; }

        public DateTime EstablishDate  { get; set; }

        public string LegalPerson { get; set; }

        public IEnumerable<CityCompany> CityCompanies { get; set; }
    }
}
namespace AspEFCore.DoMain.Models
{
    public class Mayor
    {
        public int MayOrId { get; set; }

        public int CityId { get; set; }
        public City City { get; set; }
    }
}
using System.Collections.Generic;

namespace AspEFCore.DoMain.Models
{
    public class Province
    {
        public Province()
        {
            Cities = new List<City>();
        }

        public int ProvinceId { get; set; }

        public string Name { get; set; }

        public int Population { get; set; }

        public IEnumerable<City> Cities { get; set; }
    }
}

注意:

  1. 在EFCore规则下,在实体类中凡是以实体类名称+Id的形式或直接叫Id形式的简单类型(int,或者是string)的属性,EFCore默认它就是主键,并会自动自增.
  2. EFCore上下文实例是需要Disposable的,所以我们在使用上下文的时候如果是采用new的方式创建了上下文实例,那么是需要使用using来进行包裹,如果使用的是容器注入的方式我们是不需要使用using的形式创建,也不需要手动的Disposable,容器机制会自动帮助我们进行释放.

在Asp .Net Core中使用EFCore上下文的方式有两种:

  1. 直接在using中new 出EFCore上下文实例.
  2. 使用asp.net 自带的容器,进行构造函数注入的方式来使用,那么我们就不在需要使用using来包裹,EFCore上下文实例了,因为asp.net core容器会自动释放该上下文实例资源.

在 EFCore 2.x中 在asp.net core 中如果使用了AddContext方式来注入EFCore 那么会自动添加日志记录的功能,无需在另外引用依赖项,但是在EFCore3.x中,如果我们想要在控制台中显示一些,我们需要手动在DbContext继承类中加入一些代码,详情查询EFCore对日志使用描述的 官方文档,代码如下:

我们需要在类体中加入以下静态变量.

public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });

我们需要在重写的OnConfiguring方法中配置日志工厂

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
     optionsBuilder.UseLoggerFactory(MyLoggerFactory);
 }

迁移

如果我们修改过模型类的结构或者添加或修改过一些种子数据,那么我们需要先进行Add-Migration操作,值得注意的是Add-Migration后面起的名称不能和之前已经存在的Add-Migration名称重复.

Add-Migration命令执行成功之后,我们需要执行 Update-Database命令进行迁移,到此ModelDb之前就已经是同步状态,知道下一次对Model进行添加,或修改时,我们需要再进行此类操作,进行模型和数据的同步操作,保证是同步状态.

EFCore Insert 操作

  • _context.Provinces.Add(Province);
    • MyContext开始追踪Province对象
  • _context.SaceChanges();
    • 检查所有MyContext正在追踪的对象
    • 读取每一个对象的状态
    • 生成SQL语句
    • 执行所有生成的SQL语句
    • 如果有返回数据的话,就获取这些返回数据

Insert 操作

 var province = new Province
 {
     Name = "北京",
     Population = 2_000_000
 };
 
 this._context.Province.Add(province);
 this._context.Province.AddRange(province);

批量 Insert 操作

数据源

 var province = new Province
 {
     Name = "北京",
     Population = 2_000_000
 };

 var province2 = new Province
 {
     Name = "上海",
     Population = 1_000_000
 };

 var province3 = new Province
 {
     Name = "关东",
     Population = 3_000_000
 };

添加追踪的方式1

this._context.Province.Add(province);
this._context.Province.Add(province2);
this._context.Province.Add(province3);

添加追踪的方式2

this._context.Province.AddRange(province,province2,province3);

添加追踪的方式3

this._context.Province.AddRange(new List<Province>
{
    province,province2,province
});

提交添加功能

 this._context.SaveChanges();

同时 Insert 两个不同的对象

数据源:

var province = new Province
{
    Name = "天津",
    Population = 8_000_000
};

var company = new Company()
{
    Name = "TaiDa",
    EstablishDate = new DateTime(1990,1,1),
    LegalPerson = "Secret Man"
};

添加

this._context.AddRange(province, company);

提交

this._context.SaveChanges();

批量操作的大小限制

  • 默认大小显示是由数据库Provider定的.
    • 例如Sql Server 是1000个命令
  • 如果超出该大小,那么超出的部分将作为另外的批次来执行.

如果想修改此限制也是可以的,我们可以在AddDbContext方法中,修改限制,代码如下:

 options.UseSqlServer(
                    _configuration.GetConnectionString("DefaultConnectionString"),
                    opts=>opts.MaxBatchSize(1000000));  //修改一次提交的命令的数量限制
            });

查询


//查询所有provinces表的数据
 var provinces = _context.Province.ToList();

 //带过滤条件的查询
 var provinces2 = _context.Province
     .Where(x => x.Name == "北京")
     .ToList();

 //使用Linq的方式查询
 var provinces3 = (from p in _context.Province
     where p.Name == "上海"
     select p).ToList();

值得注意的是,在进行.ToList()方法之前,无论是查询方法的方式(表达式树),还是Linq表达式的方式,都只是构建了一个查询表达式,并没有实际去查询数据库,我们可以理解成是在拼接sql的过程,只有执行到类似如.ToList()或者.ToDictionary()或者.ToArray()等方法的时候才会正在的发送生成好的sql脚本到数据库中去进行查询.

查询注意事项:

案例代码如下:

var provinces4 = _context.Province
    .Where(x => x.Name == "北京");

foreach (var province in provinces4)
{
    Console.WriteLine(province.Name);

    /*执行了一些耗时方法*/
}

上述代码的问题在于,变量provinces4此时只是相当于一个表达式树,在使用foreach对这个表达式树进行遍历时,此表达式树会生成相应的sql去请求数据库查询数据,但是如果这个foreach循环执行的时间比较长的话,会导致数据库连接长期处于被打开状态(引发数据库性能问题),此时如果有别的操作来,操作此表的话,就会出现一些意想不到的事情,所以在遍历之前,我们最好使用ToList()方法之类的方式,先将此表达式应对的数据查询到内存中(此处数据库连接就会被关闭掉),再对查询到数据进行处理.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章