三十四

本文深入解析了EFCore的CRUD操作,包括数据新增、查询、更新和删除。在新增操作中,通过Add方法将实体加入内存管理,然后通过SaveChanges提交。查询分为跟踪查询和非跟踪查询。更新操作需要跟踪查询获取数据,修改后保存。删除操作可通过跟踪或非跟踪查询实现,甚至仅凭主键就能删除数据。整个过程中,EFCore通过内存管理实体状态,确保数据一致性。
摘要由CSDN通过智能技术生成

首页新闻博问专区闪存班级                          我的博客我的园子账号设置退出登录注册登录五行缺码 博客园首页新随笔联系订阅管理随笔 - 55  文章 - 0  评论 - 37EF Core 三 、 EF Core CRUD EF Core CRUD上篇文章中,我们已经基本入门了EFCore,搭建了一个简单的EFCore项目,本文开始简单使用下EF,做增删改查的相关操作;一、数据新增操作(C) public static async void Insert_测试新增数据1()
{
var myDbContext = new MyDbContext();
if (myDbContext.TestTables.Any(p => p.Id == 1)) return;
var newEntity = new TestTable
{
Id = 1,
Name = “主表数据1”
};

        await myDbContext.TestTables.AddAsync(newEntity);
        myDbContext.SaveChanges();

        Console.WriteLine($"TestTable Insert Success");
        Console.WriteLine($"------------------------");
    }

是不是很简单的代码?so eays …
我们还是来分析下整体代码的运行;
1.首先我们自己在代码段中新增了一个实体对象,并对其字段做赋值,然后通过Add方法加入到DbSet中
2.通过DbContext.SaveChanges提交数据到数据库保存
那EF是如何偷偷的在背后帮我们完成这一切的呢?EFCore实体四状态, 如下四种状态; public enum EntityState
{
///
/// The entity is not being tracked by the context.
///
Detached = 0,
///
/// The entity is being tracked by the context and exists in the database. Its property
/// values have not changed from the values in the database.
///
Unchanged = 1,
///
/// The entity is being tracked by the context and exists in the database. It has been marked
/// for deletion from the database.
///
Deleted = 2,
///
/// The entity is being tracked by the context and exists in the database. Some or all of its
/// property values have been modified.
///
Modified = 3,
///
/// The entity is being tracked by the context but does not yet exist in the database.
///
Added = 4
}
Detached : 实体未被跟踪
Unchanged:未修改
Deleted : 删除状态
Modified:修改状态
Added:新增状态
Detached 未被跟踪状态,很多同学可能无法理解了,EFCore会默认自动跟踪实体信息,用来维护实体状态,也是方便后续提交时的处理;EFCore提供两种查询方法,跟踪查/非跟踪查,跟踪查得到的数据是Unchanged,而非跟踪查的到的数据是Detached,这两种方式我们后面详细说明,这里先简单描述下;EFCore管理内存实体
查看DbContext源码中的Add方法,跟踪方法,发现Add方法会调用到 EntityReferenceMap.cs 类中的Update方法 (下面的源码内容),此方法中EFCore会在内存中维护我们操作的实体信息,将我们操作的实体信息管理到内存中(我们的增删改查操作,EFCore都会再内存维护,方法中只是对实体状态维护,SaveChanges才会提交); public virtual void Update(
[NotNull] InternalEntityEntry entry,
EntityState state,
EntityState? oldState)
{
var mapKey = entry.Entity ?? entry;
var entityType = entry.EntityType;
if (_hasSubMap && entityType.HasDefiningNavigation())
{
if (_dependentTypeReferenceMap == null)
{
_dependentTypeReferenceMap = new Dictionary<IEntityType, EntityReferenceMap>();
}
if (!_dependentTypeReferenceMap.TryGetValue(entityType, out var dependentMap))
{
dependentMap = new EntityReferenceMap(hasSubMap: false);
_dependentTypeReferenceMap[entityType] = dependentMap;
}
dependentMap.Update(entry, state, oldState);
}
else
{
if (oldState.HasValue)
{
Remove(mapKey, entityType, oldState.Value);
}
if (!oldState.HasValue || state != EntityState.Detached)
{
switch (state)
{
case EntityState.Detached:
if (_detachedReferenceMap == null)
{
_detachedReferenceMap = new Dictionary<object, InternalEntityEntry>(ReferenceEqualityComparer.Instance);
}
_detachedReferenceMap[mapKey] = entry;
break;
case EntityState.Unchanged:
if (_unchangedReferenceMap == null)
{
_unchangedReferenceMap = new Dictionary<object, InternalEntityEntry>(ReferenceEqualityComparer.Instance);
}
_unchangedReferenceMap[mapKey] = entry;
break;
case EntityState.Deleted:
if (_deletedReferenceMap == null)
{
_deletedReferenceMap = new Dictionary<object, InternalEntityEntry>(ReferenceEqualityComparer.Instance);
}
_deletedReferenceMap[mapKey] = entry;
break;
case EntityState.Modified:
if (_modifiedReferenceMap == null)
{
_modifiedReferenceMap = new Dictionary<object, InternalEntityEntry>(ReferenceEqualityComparer.Instance);
}
_modifiedReferenceMap[mapKey] = entry;
break;
case EntityState.Added:
if (_addedReferenceMap == null)
{
_addedReferenceMap = new Dictionary<object, InternalEntityEntry>(ReferenceEqualityComparer.Instance);
}
_addedReferenceMap[mapKey] = entry;
break;
}
}
}
}
代码中就是针对不同状态的实体,EF采用不同的集合进行维护,按照我们的测试代码,会将新增实体放入上面的_addedReferenceMap 集合中,方便EFCore做提交时的操作;
EFCore SaveChanges
然后来看下将实体加入到内存集合后,提交操作到底做了什么
首先跟踪到 DbContext的 SaveChanges方法,其内部会调用StateManger.SaveChanges方法,代码如下: public virtual int SaveChanges(bool acceptAllChangesOnSuccess)
{
if (ChangedCount == 0)
{
return 0;
}
var entriesToSave = GetEntriesToSave(cascadeChanges: true);
if (entriesToSave.Count == 0)
{
return 0;
}
try
{
var result = SaveChanges(entriesToSave);
if (acceptAllChangesOnSuccess)
{
AcceptAllChanges((IReadOnlyList)entriesToSave);
}
return result;
}
catch
{
foreach (var entry in entriesToSave)
{
((InternalEntityEntry)entry).DiscardStoreGeneratedValues();
}
throw;
}
}
首先 GetEntriesToSave 方法,这个方法就是和上面的Add呼应,将EFCore加入到内存集合中管理的实体再次读取出来,得到一个entriesToSave集合,也就是需要保存的实体集合,看下其中的部分代码就是将内存集合中的数据得到 if (!hasDependentTypes)
{
var numberOfStates
= (returnAdded ? 1 : 0)
+ (returnModified ? 1 : 0)
+ (returnDeleted ? 1 : 0)
+ (returnUnchanged ? 1 : 0);

            if (numberOfStates == 1)
            {
                if (returnUnchanged)
                {
                    return _unchangedReferenceMap.Values;
                }
                if (returnAdded)
                {
                    return _addedReferenceMap.Values;
                }
                if (returnModified)
                {
                    return _modifiedReferenceMap.Values;
                }
                if (returnDeleted)
                {
                    return _deletedReferenceMap.Values;
                }
            }
            if (numberOfStates == 0)
            {
                return Enumerable.Empty<InternalEntityEntry>();
            }
        }

可以看到将不同状态的实体集合返回,得到了一个需要保存的实体集合数据,那得到需要保存的实体之后,就需要执行数据库命令了;
整体的保存入口方法还是由 DbContext 提供,DbContext.SaveChanges 方法会调用到 BatchExecutor.cs类中的Execute方法private int Execute(DbContext _, (IEnumerable, IRelationalConnection) parameters)
{
var commandBatches = parameters.Item1;
var connection = parameters.Item2;
var rowsAffected = 0;
IDbContextTransaction startedTransaction = null;
try
{
if (connection.CurrentTransaction == null
&& (connection as ITransactionEnlistmentManager)?.EnlistedTransaction == null
&& Transaction.Current == null
&& CurrentContext.Context.Database.AutoTransactionsEnabled)
{
startedTransaction = connection.BeginTransaction();
}
else
{
connection.Open();
}
foreach (var batch in commandBatches)
{
batch.Execute(connection);
rowsAffected += batch.ModificationCommands.Count;
}
startedTransaction?.Commit();
}
finally
{
if (startedTransaction != null)
{
startedTransaction.Dispose();
}
else
{
connection.Close();
}
}
return rowsAffected;
}
上诉代码中,根据得到的命令集合,循环执行命令来执行命令,最后通过事务统一来提交操作,也是确保DbContext内的事务一致性;
至此,我们EfCore的新增操作就简单分析完了,通过EFCore的DbContext来添加实体对象,通过Add方法,此时对象会加入到EFCore的内存管理集合中,不同状态对象不同的管理集合,调用SaveChanges方法保存,此时EFCore会将内存的实体对象读取出来,然后通过数据库事务统一提交;EFCore在整个操作中给我们加入了一层数据缓存层,也就是内存管理(后面会慢慢交流这一层的内容);二、数据查询 (R)数据查询的内容上一篇入门文章中我已经说了相关方法,这里再把调用方式同步下
EF 的数据查询分为两种,跟踪查询和非跟踪查询;
1.跟踪查询是默认方式,默认EF查询出来的数据是跟踪模式(也可以手动调整),用于对数据做更新等数据库操作;
2.非跟踪查询模式,此模式用于单纯的数据查询,后续不需要对数据做相关修改,因为不需要对实体做调整的监测,所以会比跟踪查询相对快一些;
两种方式各有利弊,需要根据自己的业务实际需要来选择;
两种模式的文档说明(https://docs.microsoft.com/zh-cn/ef/core/querying/tracking)var myDbContext = new MyDbContext();
var list = myDbContext.TestTables.ToList();
Console.WriteLine( " T e s t T a b l e C o u n t : l i s t . C o u n t " ) ; i f ( ! l i s t . A n y ( ) ) r e t u r n ; C o n s o l e . W r i t e L i n e ( "TestTable Count: {list.Count}"); if (!list.Any()) return; Console.WriteLine( "TestTableCount:list.Count");if(!list.Any())return;Console.WriteLine(“TestTable Detail ---------------- “);
foreach (var item in list)
{
Console.WriteLine(KaTeX parse error: Expected 'EOF', got '}' at position 53: …); }̲ Co…”------------------------”);
三、数据更新 (U)数据更新操作,必须使用跟踪查询得到数据,然后修改得到的实体信息,再通过DbContext的SaveChanges提交数据即可;
三部曲:
1.跟踪查询得到数据
2.修改实体数据
3.DbContext.SaveChanges保存数据 var myDbContext = new MyDbContext();
var list = myDbContext.TestTables.AsTracking().ToList();
var firstEntity = list.FirstOrDefault(p => p.Id == 1);
if (firstEntity != null) firstEntity.Name = " f i r s t E n t i t y . N a m e Q u e r y 跟 踪 查 询 " ; m y D b C o n t e x t . S a v e C h a n g e s ( ) ; C o n s o l e . W r i t e L i n e ( "{firstEntity.Name} Query_跟踪查询"; myDbContext.SaveChanges(); Console.WriteLine( "firstEntity.NameQuery";myDbContext.SaveChanges();Console.WriteLine(“------------------------”);
四、数据删除 (D)1.使用跟踪查询,将数据查询出来
2.通过DbSet将其Remove(也是再内存集合中做了标记,将其放入了remove集合中)
3.SaveChanges提交保存 var myDbContext = new MyDbContext();
            var entity = myDbContext.TestTables.FirstOrDefault(p => p.Id == 1);
            if (entity != null)
                myDbContext.TestTables.Remove(entity);
            myDbContext.SaveChanges();
有没有发现问题,(⊙o⊙)? 删除个数据还要查询出来?业务场景中,很多都是前端传入主键ID,执行执行相关表的数据删除,那是否可以使用非跟踪查询模式呢?
验证下 … var myDbContext = new MyDbContext();
            var entity = myDbContext.TestTables.AsNoTracking().FirstOrDefault(p => p.Id == 1);
            if (entity != null)
                myDbContext.TestTables.Remove(entity);
            myDbContext.SaveChanges();
结果当然是可以删除啦,😄
那既然是非跟踪可以删除,也意味着自己构建的实体可以删除,那是否只需要主键就可以删除了 ? var myDbContext = new MyDbContext();
var entity = new TestTable()
{
Id = 1
};
myDbContext.TestTables.Remove(entity);
myDbContext.SaveChanges();
如上的代码,确实也是可以的,删除成功 !!!至此我们完成了EFCore的入门简单操作,基本都是简单的单表操作,只是为了演示整个EFCore的代码结构,大家可以自己上手尝试下,后续我们将开始EFCore相关的骚操作以及一些进阶操作 分类: EF Core 标签: EF Core好文要顶 关注我 收藏该文 五行缺码
关注 - 7
粉丝 - 21 +加关注 1 0

« 上一篇: EF Core 二 、 入门 EF Core posted @ 2020-11-23 16:48  五行缺码  阅读(438)  评论(0)  编辑  收藏

刷新评论刷新页面返回顶部

发表评论 【福利】注册AWS账号,立享12个月免费套餐 编辑预览 7693b08a-a8f6-49f3-f45a-08d88556cc23 Markdown 帮助自动补全 不改了退出 订阅评论 [Ctrl+Enter快捷键提交]

首页 新闻 博问 专区 闪存 班级 【推荐】News: 大型组态、工控、仿真、CADGIS 50万行VC++源码免费下载
【推荐】从零开始的RPG游戏制作教程,来《魔兽争霸III》共同成长
【推荐】了不起的开发者,挡不住的华为,园子里的品牌专区
【推荐】未知数的距离,毫秒间的传递,声网与你实时互动
【福利】AWS携手博客园为开发者送免费套餐与抵扣券
【推荐】 阿里云折扣价格返场,错过再等一年
相关博文:
· EFcoremysql
· EFCore批处理语句
· ASP.NETCore2.1使用EFCore操作MySql数据库
· C#之.netcore–EFcodefirst连接Mysql数据库
· .netcore使用EFcore从数据库中生成实体类(MySQL,Oracle,SQLServer)
» 更多推荐…最新 IT 新闻:
· 整整10年了!这就是微信的第一段代码
· Google Assistant现在可以用来控制智能灯具
· 微软投资2700万欧元在爱尔兰开设工程中心 设立200个新岗位
· 开发人员已进行175小时《赛博朋克2077》 仍未打完
· 谷歌Stadia云游戏即将在iPhone上推出公测版本
» 更多新闻…

公告 昵称: 五行缺码
园龄: 6年11个月
粉丝: 21
关注: 7 +加关注

< 2020年11月> 日一二三四五六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 1 2 3 4 5 6 7 8 9 10 11 12

搜索    常用链接 我的随笔我的评论我的参与最新评论我的标签我的标签Docker(4) EF Core(3) 数据库(3) ABP(2) autofac ioc di(1) C# .net Email QQ 163(1) .NET C# 按需加载 延迟加载 性能优化(1) .netcore asp.net nginx supervisor(1) .netcore asp.net nuget(1) .netcore signalr redis 负载均衡(1) 更多 随笔分类 .netcore(7) ABP(2) Angularjs(1) asp.net core(1) Docker(5) dojo(1) EF Core(3) Sonar(1) Web Api(2) WF(15) 数据库(3) 随笔档案 2020年11月(3) 2020年10月(2) 2020年9月(8) 2020年8月(1) 2018年12月(1) 2018年4月(1) 2018年3月(8) 2017年4月(2) 2017年2月(1) 2016年4月(1) 2015年7月(1) 2014年10月(12) 2014年9月(3) 2014年8月(11) 最新评论1. Re:EF Core 二 、 入门 EF Core谢谢分享–沈赟2. Re:EF Core 二 、 入门 EF Core@流光_…–五行缺码3. Re:EF Core 二 、 入门 EF Core啥“当然Code First也不会丢掉的”,楼主大胆点,就喜欢DbFirst的粗暴直接–流光_4. Re:EF Core 一、重识 EF感谢分享,可以以EFCore为主,辅以FreeSql, SqlSugar, dapper–WebAssembly5. Re:EF Core 一、重识 EF还记得手码Connection,command的时候,那时候orm就是自己封装的一套,现在现成的好用的orm框架太多了…–五行缺码阅读排行榜 1. 代码检查工具 Sonar 安装&使用(5486) 2. Web API 之承载宿主IIS,SelfHost,OwinSelfHost(1737) 3. asp.net core 五 SignalR 负载均衡(1697) 4. C# QQ & 163 邮件发送(1523) 5. Web API 之SelfHost与OwinSelfHots加载外部程序(920) 评论排行榜 1. Web API 之SelfHost与OwinSelfHots加载外部程序(13) 2. ABP 数据访问 - IRepository 仓储(5) 3. EF Core 一、重识 EF(4) 4. asp.net core 五 SignalR 负载均衡(4) 5. EF Core 二 、 入门 EF Core(3) 推荐排行榜 1. asp.net core 五 SignalR 负载均衡(12) 2. EF Core 二 、 入门 EF Core(4) 3. Docker:四、Docker进阶 Windows Docker IIS 部署(4) 4. ABP 数据访问 - IRepository 仓储(3) 5. Web API 之SelfHost与OwinSelfHots加载外部程序(3)

Copyright © 2020 五行缺码
Powered by .NET 5.0.0 on Kubernetes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值