当前位置: 首页 > news >正文

02020402 EF Core基础02-EF Core数据的增删改查

02020402 EF Core基础02-EF Core数据的增删改查

1. EF Core数据的增删改查(视频3-3)

  • 创建.NET Core控制台项目,项目文档如下。
// Book.cs
using System;namespace EF CoreDemo
{public class Book{public long Id { get; set; } //主键public string Title { get; set; }//标题public DateTime PubTime { get; set; }//发布日期public double Price { get; set; }// 价格public string AuthorName { get; set; } // 新建属性(对应数据表中的行)}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// BookConfig.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;namespace EF CoreDemo
{class BookConfig : IEntityTypeConfiguration<Book> // 泛型接口,这个Book表示是与哪个实体类配置。{public void Configure(EntityTypeBuilder<Book> builder){builder.ToTable("T_Books"); // T_Books表与Book实体类相对应builder.Property(e => e.Title).HasMaxLength(50).IsRequired(); // @1builder.Property(e => e.AuthorName).HasMaxLength(20).IsRequired(); // @2}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Person.cs
namespace EF CoreDemo
{public class Person{public long Id { get; set; }public long Name { get; set; }public int Age { get; set; } // 修改Age为int类型public string BirthPlace { get; set; } // 新增属性public double? Salary { get; set; } // 可为空的double类型}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// PersonConfig.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;namespace EF CoreDemo
{class PersonConfig : IEntityTypeConfiguration<Person>{public void Configure(EntityTypeBuilder<Person> builder){builder.ToTable("T_Persons");}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Dog.cs
namespace EF CoreDemo
{public class Dog{public long Id { get; set; } //主键public string Name { get; set; }//标题}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// MyDbContext.cs
using Microsoft.EntityFrameworkCore;namespace EF CoreDemo
{class MyDbContext : DbContext{public DbSet<Book> Books { get; set; }public DbSet<Person> Persons { get; set; }public DbSet<Dog> Dogs { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){string connStr = "Server=.;Database=CoreDataDB;Trusted_Connection=True;MultipleActiveResultSets=true";optionsBuilder.UseSqlServer(connStr);}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);}}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Program.cs
using System;namespace EF CoreDemo
{class Program{static void Main(string[] args){}}
}
  • 通过EF Core创建数据表
PM> add-migration addbirth
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> update-database
Build started...
Build succeeded.
Applying migration '20250918125952_Init'.
Done.
PM> 

2. 插入数据

2.1 插入数据步骤
1、只要操作Books属性,就可以向数据库中增加数据,但是通过C#代码修改Books中的数据只是修改了内存中的数据。对Books做修改后,需要调用DbContext的异步方法SaveChangesAsync()把修改保存到数据库。也有同步的保存方法SaveChanges(),但是用EF Core都推荐用异步方法。
2、EF Core默认会跟踪(Track)实体类对象以及DbSet的改变。
3、演示数据插入。
2.2 插入数据示例
using System;
using System.Threading.Tasks;namespace EF CoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()) // ctx相当于逻辑上的数据库{Dog dog = new Dog();dog.Name = "Trump"; // 因为Dogs表的Id是自增的,因此只需要给Name赋值即可。ctx.Dogs.Add(dog); // 将dog对象添加到Dogs这个逻辑上的表里面。// ctx.SaveChanges(); // 保存修改,SaveChanges()是同步方法,相当于在程序包管理器控制台执行update-databaseawait ctx.SaveChangesAsync(); // 保存修改,异步方法。}Console.WriteLine("数据插入成功");Console.ReadLine();}}
}控制台输出:
数据插入成功
  • 通过SSMS查看数据
图片链接丢失

3. 查询数据

3.1 给数据库插入数据用于查询
using System;
using System.Threading.Tasks;namespace EF CoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()) // ctx相当于逻辑上的数据库{Book b1 = new Book { AuthorName = "杨中科", Title = "零基础趣学C语言", Price = 59.8, PubTime = new DateTime(2019, 3, 1) };Book b2 = new Book { AuthorName = "Robert Sedgewick", Title = "算法第4版", Price = 99, PubTime = new DateTime(2012, 10, 1) };Book b3 = new Book { AuthorName = "吴军", Title = "数学之美", Price = 69, PubTime = new DateTime(2020, 5, 1) };Book b4 = new Book { AuthorName = "杨中科", Title = "程序员的SQL经典", Price = 52, PubTime = new DateTime(2008, 9, 1) };Book b5 = new Book { AuthorName = "吴军", Title = "文明之光", Price = 246, PubTime = new DateTime(2017, 3, 1) };ctx.Books.Add(b1);ctx.Books.Add(b2);ctx.Books.Add(b3);ctx.Books.Add(b4);ctx.Books.Add(b5);await ctx.SaveChangesAsync();}Console.WriteLine("数据插入成功");Console.ReadLine();}}
}控制台输出:
数据插入成功
  • 数据库中的数据
图片链接丢失
3.2 查询数据
1、DbSet实现了IEnumerable<T>接口,因此可以对DbSet实施Linq操作来进行数据查询。EF Core会把Linq操作转换为SQL语句。面向对象,而不是面向数据库(SQL)。
2、ctx.Books.Where(b => b.Price > 80)
Book b1 = ctx.Books.Single(b => b.Title== "零基础趣学C语言");
Book b2 = ctx.Books.FirstOrDefault(b=>b.Id==9);
3、可以使用OrderBy操作进行数据的排序
IEnumerable<Book> books = ctx.Books.OrderByDescending(b => b.Price);
3.3 查询数据示例01
// Program.cs
using System;
using System.Threading.Tasks;
using System.Linq;namespace EF CoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()){IQueryable<Book> book01 = ctx.Books.Where(b => b.Price > 80); // @1foreach (Book book in book01){Console.WriteLine(book.Title);}Console.WriteLine("********************");Book book02 = ctx.Books.Single(b => b.Title == "零基础趣学C语言"); // @2Console.WriteLine(book02);Console.WriteLine(book02.AuthorName);Console.WriteLine("********************");IQueryable<Book> book03 = ctx.Books.OrderBy(b => b.Price); // 根据价格排序foreach(Book book in book03){Console.WriteLine(book.Title + "的价格为:" + book.Price);}Console.WriteLine("********************");IQueryable<Book> book04 = ctx.Books.OrderBy(b => b.Price).Where(b => b.Price > 80); // 根据价格排序,并且只取价格高于80的。foreach (Book book in book04){Console.WriteLine(book.Title + "的价格为:" + book.Price);}}// await ctx.SaveChangesAsync();Console.ReadLine();}}
}控制台输出:
算法第4版
文明之光
********************
EF CoreDemo.Book
杨中科
********************
程序员的SQL经典的价格为:52
零基础趣学C语言的价格为:59.8
数学之美的价格为:69
算法第4版的价格为:99
文明之光的价格为:246
********************
算法第4版的价格为:99
文明之光的价格为:246说明:
1. 在@1处,Where返回值类型为IQueryable类型。
1.1 IQueryable又继承自IEnumerable,IQueryable是EF Core里面的类型。
1.2 之前讲的LINQ有Where返回的是IEnumerable。
2. 在@2处,确认只有一本书,返回值就不是一个集合了。此时就不写IQueryable,而是直接返回Book类型。
3.4 查询数据示例02
1、GroupBy也可以
var groups = ctx.Books.GroupBy(b => b.AuthorName).Select(g => new { AuthorName = g.Key, BooksCount = g.Count(), MaxPrice = g.Max(b => b.Price) });
foreach(var g in groups)
{Console.WriteLine($"作者名:{g.AuthorName},著作数量:{g.BooksCount},最贵的价格:{g.MaxPrice}");
}
2、大部分Linq操作都能作用于EF Core。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Program.cs
using System;
using System.Threading.Tasks;
using System.Linq;namespace EFCoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()){var item = ctx.Books.GroupBy(b => b.AuthorName).Select(g => new { Name=g.Key, BooksCount=g.Count(), MaxPrice = g.Max(b => b.Price)});foreach (var bk in item){Console.WriteLine($"{bk.Name}, {bk.BooksCount}, {bk.MaxPrice}");}}Console.ReadLine();}}
}控制台输出:
Robert Sedgewick, 1, 99
吴军, 2, 246
杨中科, 2, 59.8

4. 修改数据

  • 要对数据进行修改,首先需要把要修改的数据查询出来,然后再对查询出来的对象进行修改,然后再执行SaveChangesAsync()保存修改。
// 伪代码
var b = ctx.Books.Single(b=>b.Title== "数学之美");
b.AuthorName = "Jun Wu";
await ctx.SaveChangesAsync();
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 修改前数据库中信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
2	算法第4版	2012-10-01 00:00:00.0000000	99	Robert Sedgewick
3	数学之美	2020-05-01 00:00:00.0000000	69	吴军
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	246	吴军
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 修改数据:Program.cs
using System;
using System.Threading.Tasks;
using System.Linq;namespace EFCoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()){var b = ctx.Books.Single(b => b.Title == "数学之美"); // 找到对象,明确只有一个用Singleb.AuthorName = "Junwu"; // 修改对象属性await ctx.SaveChangesAsync(); // 更新数据库}Console.WriteLine("修改数据成功!");Console.ReadLine();}}
}控制台输出:
修改数据成功!
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 修改后数据库中信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
2	算法第4版	2012-10-01 00:00:00.0000000	99	Robert Sedgewick
3	数学之美	2020-05-01 00:00:00.0000000	69	Junwu // 这里已经将吴军修改为Junwu
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	246	吴军

5. 删除数据

  • 删除也是先把要修改的数据查询出来,然后再调用DbSet或者DbContext的Remove方法把对象删除,然后再执行SaveChangesAsync()保存修改。
// 伪代码
var b = ctx.Books.Single(b => b.Title == "数学之美");
ctx.Remove(b);//也可以写成ctx.Books.Remove(b);
await ctx.SaveChangesAsync();
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 删除前数据库中信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
2	算法第4版	2012-10-01 00:00:00.0000000	99	Robert Sedgewick
3	数学之美	2020-05-01 00:00:00.0000000	69	Junwu
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	246	吴军
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 删除数据:Program.cs
using System;
using System.Threading.Tasks;
using System.Linq;namespace EFCoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()){var b = ctx.Books.Single(b => b.Id == 2); // 找到对象,明确只有一个用Singlectx.Books.Remove(b); // 删除对象await ctx.SaveChangesAsync(); // 更新数据库}Console.WriteLine("删除数据成功!");Console.ReadLine();}}
}控制台输出:
删除数据成功!
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 修改后数据库中信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
3	数学之美	2020-05-01 00:00:00.0000000	69	Junwu
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	246	吴军说明:Id为2的数据项已经删除。

6. 批量修改数据

  • 价格大于60的所有书涨1块钱
// 数据库已有信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
3	数学之美	2020-05-01 00:00:00.0000000	69	Junwu
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	246	吴军
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 给价格大于60的所有书涨1块钱:Program.cs
using System;
using System.Threading.Tasks;
using System.Linq;namespace EFCoreDemo
{class Program{static async Task Main(string[] args){// @1 插入数据using (MyDbContext ctx = new MyDbContext()){var books = ctx.Books.Where(b => b.Price > 60); foreach(var bk in books){bk.Price = bk.Price + 1;}await ctx.SaveChangesAsync(); // 更新数据库}Console.WriteLine("价格大于60的书涨1块钱成功!");Console.ReadLine();}}
}控制台输出:
价格大于60的书涨1块钱成功!
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 更新后的数据库信息
Id	Title	PubTime	Price	AuthorName
1	零基础趣学C语言	2019-03-01 00:00:00.0000000	59.8	杨中科
3	数学之美	2020-05-01 00:00:00.0000000	70	Junwu
4	程序员的SQL经典	2008-09-01 00:00:00.0000000	52	杨中科
5	文明之光	2017-03-01 00:00:00.0000000	247	吴军

7. 跟踪数据库

7.1 跟踪数据库的步骤
  • SSMS → 工具 → SQL Server Profiler → 连接到服务器面板 → 连接 → 跟踪属性(默认接口) → 运行 → 执行.NET Core控制台程序 → 可以看到如下执行SQL语句的代码。
Typora-Logo
查询的SQL语句

更新的SQL语句
  • 从上述两张图片可以得出如下结论
    • EF Core首先从数据库拿到数据,然后每个数据都需要update更新一次,有5条就执行5次。如果有1万条,就会执行1万条update。
    • 如果直接执行SQL语句,只需要一个update即可。
    • 对于数量比较大的,或者需要批量的更新或者删除,相对于直接执行SQL语句来说,EF Core的性能相对比较低。

8. EF Core关于批量处理数据的性能损失

8.1 EF Core处理批量数据性能损失的原因
1、目前批量修改、删除多条数据的方法。
局限性:性能低:查出来,再一条条Update、Delete,而不能执行Update ... where;delete ... where;
2、官方目前还没有支持高效的批量Update、Delete,有在后续版本中增加,但是目前只是前期意见征询阶段。
  • EF Core在目前为止(讲课时间为:2023.07.21日)还没有高效的,批量的update和delete方法。这样做的目的,微软官方给出了如下理由。
    • 为了保证内存中对象状态的一致性,EF Core在设计之初就没有考虑到批量的update和delete。
    • 注:课程弹幕上提示.NET Core 7.0有了ExecuteUpdate和ExecuteDelete,用来批量的update和delete。
8.2 老师自己开发的一个批量、修改的开源项目
我实现了一个开源的高效批量修改、删除的开源项目。
Zack.EFCore.Batch https://github.com/yangzhongke/Zack.EFCore.Batch
  • 用法:这个包可能存在数据库中数据删除了,但是还能查出来。这是因为数据缓存的问题,这个问题受限于EF Core,关于这个包了解即可。
// 批量删除
await ctx.DeleteRangeAsync<Book>(b => b.Price > n || b.AuthorName == "zack yang"); // 批量删除
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 批量修改
await ctx.BatchUpdate<Book>() .Set(b => b.Price, b => b.Price/3).Set(b => b.Title, b => s).Set(b => b.PubTime, b=> DateTime.Now).Where(b => b.Id > n || b.AuthorName.StartsWith("Zack")).ExecuteAsync();

结尾

书籍:ASP.NET Core技术内幕与项目实战

视频:https://www.bilibili.com/video/BV1pK41137He

著:杨中科

ISBN:978-7-115-58657-5

版次:第1版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

http://www.hskmm.com/?act=detail&tid=9958

相关文章:

  • conda 无法安装依赖 CondaHTTPError: HTTP 000 CONNECTION FAILED for url: tsinghua tencentaliyun
  • 牛客刷题-Day2
  • 图解支付系统账务系统核心设计 - 智慧园区
  • vulnhub(持续更新)
  • 小爱同学连接电脑进行交互 教程
  • 网络流初步浅谈:EK与Dinic
  • 解码C语言结构体
  • 已完成今日求所有满足长为 $a$ 的和为 $b$ 的按位或为 $c$ 的非负整数序列的异或和的异或和大学习
  • Hello Yqc!
  • 2025.9.19——卷9-10选择
  • 软件工程学习日志2025.9.19
  • ECT-OS-JiuHuaShan 框架元推理,是人类良医与福音
  • upload-labs全通关
  • SAPO去中心化训练:多节点协作让LLM训练效率提升94%
  • mybatis-plus学习笔记
  • 区间问题
  • 操作系统,知识体系一共包含哪些部分? - 实践
  • vscode 下载 VS Code Server 卡住(无需手动下载)
  • 查询本地IPV6 地址
  • 解决 Ubuntu 25.04 下 make menuconfig 报 ncurses 错误的问题 - 指南
  • web359
  • web360
  • 缺失的第一个正数-leetcode
  • hbase的安装应用
  • 如何在后端优雅地生成并传递动态错误提示?
  • 深入解析:Java全栈开发面试实录:从基础到微服务的实战解析
  • web358
  • 04_Redis凭啥这么牛:核心特性剖析
  • WPF包
  • 惊爆!Flutter消息通道的超神全解析!