Entity Framework Core 3.1 入门(四)增删改查

此入门教程是记录下方参考资料视频的过程,本例基于Entity Framework Core 3.1
开发工具:Visual Studio 2019

参考资料:https://www.bilibili.com/video/BV1xa4y1v7rR

目录

Entity Framework Core 3.1 入门(一)创建项目

Entity Framework Core 3.1 入门(二)创建数据库和迁移(Migration)文件

Entity Framework Core 3.1 入门(三)一对一、多对多

Entity Framework Core 3.1 入门(四)增删改查

Entity Framework Core 3.1 入门(五)关联数据的添加和查询

Entity Framework Core 3.1 入门(六)一对一和多对多关系的增删改查

Entity Framework Core 3.1 入门(七)执行原生SQL语句

Entity Framework Core 3.1 入门(八)在 ASP.NET Core 中配置 Entity Framework Core

控制台输出执行的SQL语句

  1. Demo.Data 项目下使用 NuGet 安装 Microsoft.Extensions.Logging.Console
  2. DbContext中添加方法
public static readonly ILoggerFactory CnosoleLoggerFactory = LoggerFactory.Create(builder =>
{
      //添加过滤,只输出数据库命令
      builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
});

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
      //UseLoggerFactory(),添加日志功能
      //EnableSensitiveDataLogging(),生成的SQL语句显示参数实际的值
      optionsBuilder.UseLoggerFactory(CnosoleLoggerFactory)
            .EnableSensitiveDataLogging();
}

添加

  1. 添加一个数据,直接上代码
public static void Func_01()
{
      //使用完调用Dispose方法清理资源
      //C# 8.0的语法,using不需要加小括号
      using var context = new DemoContext();

      var serieA = new League
      {
          Country = "Italy",
          Name = "Serie A"
      };

      //执行完Add方法后,仍然没有与数据库进行交互
      context.Leagues.Add(serieA);

      //调用此处执行SQL语句
      //SaveChanges()方法会检查所有追踪对象的状态
      //然后在同一个事务中对增删改的变化执行SQL语句
      //一个失败就整体回滚
      //执行成功会返回影响的行数
      var count = context.SaveChanges();

      Console.WriteLine("==================");
      Console.WriteLine(count);
}
  1. 添加多个相同类型的数据
public static void Func_02()
{
      using var context = new DemoContext();

      var serieB = new League
      {
          Country = "Italy",
          Name = "Serie B"
      };
      var serieC = new League
      {
          Country = "Italy",
          Name = "Serie C"
      };

      //两种形式
      context.Leagues.AddRange(serieB, serieC);
      context.Leagues.AddRange(new List<League> { serieB, serieC });

      var count = context.SaveChanges();

      Console.WriteLine("==================");
      Console.WriteLine(count);
}
  1. 添加多个不同类型的数据
public static void Func_03()
{
      using var context = new DemoContext();

      var serieA = context.Leagues.Single(x => x.Name == "Serie A");
      var serieB = new League
      {
          Country = "Italy",
          Name = "Serie B"
      };
      var serieC = new League
      {
          Country = "Italy",
          Name = "Serie C"
      };

      var milan = new Club
      {
          Name = "AC Milan",
          City = "Milan",
          DateOfEstablishment = new DateTime(1899, 12, 16),
          League = serieA
      };

      context.AddRange(serieB, serieC, milan);
      //context也可以添加一个数据
      //context.Add();

      var count = context.SaveChanges();

      Console.WriteLine("==================");
      Console.WriteLine(count);
}

查询

Linq 查询

public static void Func_04()
{
      //Linq查询有两种方式
      //1、Linq中的方法去查询
      //2、Linq语句查询

      using var context = new DemoContext();

      //查询所有结果
      //调用ToList()方法时才会访问数据库
      //var leagues = context.Leagues.ToList();

      //查询所有结果,条件查询
      //var leagues = context.Leagues.Where(x => x.Country == "Italy").ToList();

      //Linq语句,查询所有结果
      //var league = (from lg in context.Leagues select lg).ToList();

      //Linq语句,查询所有结果,条件查询
      //var league = (from lg in context.Leagues where lg.Country == "Italy" select lg).ToList();

      //如果查询的条件像上面一样写死,那么(生成)执行的SQL语句就是写死的
      //如果用变量作为查询条件,那么就会使用参数查询
      //var italy = "Italy";
      //var league = context.Leagues.Where(x => x.Country == italy).ToList();

      //模糊查询,条件为 %e%,两种形式
      //var league = context.Leagues.Where(x => x.Country.Contains("e")).ToList();

      //var league = context.Leagues.Where(x => EF.Functions.Like(x.Country, "%e%")).ToList();

      //遇到foreach也会去查询数据库,保持数据库连接直到循环结束
      //如果循环体是耗时操作,可能导致数据冲突,所以尽量不要这么写
      //建议先ToList(),再对查询的结果进行操作
      //foreach (var item in context.Leagues)
      //{
      //    Console.WriteLine(item.Name);
      //}

      //针对主键进行查询,两种形式
      //只会生成一次SQL语句
      //因为context会追踪查询出来的数据,Find()再执行时,如果context能在内存里找到数据,那么就不会去数据库查询
      //只有Find()方法会这样执行
      //var first = context.Leagues.SingleOrDefault(x => x.Id == 2);
      //var one = context.Leagues.Find(2);

      //Console.WriteLine(first?.Name);
      //Console.WriteLine(one?.Name);

      //Last()和LastOrDeafult()方法查询必须排序
      //OrderBy(),正向排序
      //OrderByDescending(),方向排序
      //var last = context.Leagues.OrderBy(x => x.Id).LastOrDefault(x => x.Name.Contains("e"));

}

常用的查询方法(看帮助文档):
  ToList(),返回集合
  First(),返回(符合条件的第)一个数据,必须有一个数据,没有数据就会报错,方法中可以直接写条件,不需要Where()
  FirstOrDefaule(),返回(符合条件的第)一个数据,可以没有数据,方法中可以直接写条件,不需要Where()
  Single(),返回序列的唯一元素;如果该序列并非恰好包含一个元素,则会引发异常。
  SingleOrDefault(),返回序列中的唯一元素;如果该序列为空,则返回默认值;如果该序列包含多个元素,此方法将引发异常。
  Last()
  LastOrDefaule()
实际应用中,经常使用OrDefault的方法

Find(),根据主键查找,属于DbSet的方法

Count()
LongCount()
Min()
Max()
Average()
Sum()

删除

直接上代码

public static void Func_05()
{
      using var context = new DemoContext();

      //Delete
      //只能删除被context追踪的数据,只有先查询出来才能被追踪
      var milan = context.Clubs.Single(x => x.Name == "AC Milan");

      //调用删除方法,四种
      //context.Clubs.Remove(milan);
      //context.Remove(milan);
      //删除多个结果
      //context.Clubs.RemoveRange(milan, milan);
      //context.RemoveRange(milan, milan);

      var count = context.SaveChanges();
      Console.WriteLine("==============");
      Console.WriteLine(count);
}

修改

  1. 修改数据
public static void Func_06()
{
      using var context = new DemoContext();

      //只能修改被context追踪的数据,只有先查询出来才能被追踪
      var league = context.Leagues.First();

      //context知道league.Name被修改,设置为修改状态
      league.Name += "~~";
      //执行对应的SQL语句
      var count = context.SaveChanges();
      Console.WriteLine("==============");
      Console.WriteLine(count);
}
  1. 修改多个数据
public static void Func_07()
{
      using var context = new DemoContext();

      //Skip(),跳过序列中指定数量的元素
      //Take(),从序列的开头返回指定数量的连续元素。
      var leagues = context.Leagues.Skip(1).Take(3).ToList();

      //不符合实际应用
      foreach (var league in leagues)
      {
          league.Name += "~~";
      }

      var count = context.SaveChanges();
      Console.WriteLine("==============");
      Console.WriteLine(count);
}
  1. 修改数据,模拟前端数据传递到后端(AsNoTracking(),数据离线)
public static void Func_08()
{
      using var context = new DemoContext();

      //AsNoTracking(),不对数据进行变化追踪
      //在一些情况下,我们只需要查询返回一个只读的数据记录,而不会对数据记录进行任何的修改。
      //使用AsNoTracking()会有显着的性能提升
      var league = context.Leagues.AsNoTracking().First();

      league.Name += "++";

      //Update(),将数据添加到追踪范围内,未追踪的数据一定要执行Update(),否则会报错
      //也有UpdateRange(),context也有
      //使用Update(),会将所有属性都设置为修改状态,也可以做到只修改一个属性
      context.Leagues.Update(league);

      //设置状态,实现部分字段修改
      context.Entry(league).Property("Id").IsModified = false;

      var count = context.SaveChanges();
      Console.WriteLine("==============");
      Console.WriteLine(count);
}

设置全局不追踪

在DbContext的构造器中配置,本案例不使用。

public DemoContext(DbContextOptions<DemoContext> options):base(options)
{
      ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}

增删改查 结束

posted @ 2021-02-03 15:16  .NET好耶  阅读(629)  评论(0编辑  收藏  举报