前言

本文来自和何镇汐大哥的探讨,很多时候我习惯于和别人交流过后会思考一些问题,无论是天马行空还是浅薄的想法都会记录下来,或许看到此博文的您能给我更多的思考,与人交流总能收获很多东西,出发点不一样则结论 不一样,思维方式不一样则路径不一样,愿你我共同进步。

EntityFramework Core无跟踪视图

首先依然给出本文需要用到的两个实体,如下:

    public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; }
public byte Status { get; set; }
public bool IsDeleted { get; set; }
public ICollection<Post> Posts { get; set; } = new List<Post>();
}
    public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime ModifiedTime { get; set; } public int BlogId { get; set; }
public Blog Blog { get; set; } }

在EF Core中给我们提供了Update和UpdateRange方法,这两个方法你说作用大吧,我看作用也没有那么大。要利用这两个方法,必须对值进行一一赋值,如下:

            var dbContext = new EFCoreDbContext();
var dbBlog = dbContext.Blogs.Include(d => d.Posts).FirstOrDefault(d => d.Id == );
dbBlog.Name = "Jeffcky";
foreach (var post in dbBlog.Posts)
{
post.Name = "《你必须掌握的EntityFramework 6.x与Core 2.0》";
}
dbContext.Update(dbBlog);
dbContext.SaveChanges();

在EF 6.x中缺失Update和UpdateRange方法,但是它可以进行如下更新啊不是。

            var dbContext = new EFCoreDbContext();
var newBlog = new Blog()
{
Id = ,
Name = "Jeffcky1",
IsDeleted = false,
Status = ,
Url = "https://www.cnblogs.com/CreateMyself",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now,
Posts = new List<Post>()
{
new Post()
{
Id = ,
BlogId = ,
Name = "EF Core TrackGraph",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now
}
}
}; var dbBlog = dbContext.Blogs.Include(d => d.Posts).FirstOrDefault(d => d.Id == );
dbContext.Entry(dbBlog).CurrentValues.SetValues(newBlog);
dbContext.SaveChanges();

不太了解详情的童鞋可能就说了在EF Core中也可以利用上述CurrentValues来指定更新列啊,如果您这样想那就大错特错了,来我们在EF Core中同样运行上述代码通过对比前后表中数据看看。

更新前

更新后

我们通过对比可看到,导航属性对应的表没有进行更新,不要问我为啥,在前面我也有讲过在EF Core中这种情况类似于和添加一样通过手动这是状态为Added,在EF 6.x中只要更新主表则对应与之相关的导航属性也会更新,但是在EF Core中只会更新主表,EF 6.x这么好的指定更新反而被剔除了,实在不应该啊。有人说赋值两次啊,不好意思也不行,如下:

            var dbContext = new EFCoreDbContext();
var newBlog = new Blog()
{
Id = ,
Name = "Jeffcky1",
IsDeleted = false,
Status = ,
Url = "https://www.cnblogs.com/CreateMyself",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now,
Posts = new List<Post>()
{
new Post()
{
Id = ,
BlogId = ,
Name = "EF Core TrackGraph",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now
}
}
}; var dbBlog = dbContext.Blogs.Include(d => d.Posts).FirstOrDefault(d => d.Id == );
dbContext.Entry(dbBlog).CurrentValues.SetValues(newBlog);
dbContext.Entry(dbBlog.Posts).CurrentValues.SetValues(newBlog.Posts);
dbContext.SaveChanges();

上述这种方式对关系映射是不行的,但是若是复杂属性则是可以,如下:

    [Owned]
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
} public class Order
{
public int Id { get; set; }
public StreetAddress ShippingAddress { get; set; }
}

            var dbContext = new EFCoreDbContext();
var order = dbContext.Orders.FirstOrDefault();
order.ShippingAddress.City = "city";
order.ShippingAddress.Street = "street";
dbContext.SaveChanges();

这样更新肯定是可以的,我们不做过多探讨,利用CurrentValues只能进行两次赋值才行,如下。

            var newOrder = new Order()
{
Id = ,
ShippingAddress = new StreetAddress()
{
City = "city",
Street = "street"
}
};
var dbContext = new EFCoreDbContext();
var order = dbContext.Orders.FirstOrDefault();
dbContext.Entry(order).CurrentValues.SetValues(newOrder);
dbContext.Entry(order.ShippingAddress).CurrentValues.SetValues(newOrder.ShippingAddress);
var result = dbContext.SaveChanges();

让我们再次回到更新Blog,除了利用CurrentValues指定更新外,我们还可以在查询Posts时不进行显式加载,然后调用直接将更新newBlog赋值与dbBlog,这种方式和手动赋值本质一样,但是至少不用一一赋值不是,如下:

            var dbContext = new EFCoreDbContext();
var newBlog = new Blog()
{
Id = ,
Name = "Jeffcky1",
IsDeleted = false,
Status = ,
Url = "https://www.cnblogs.com/CreateMyself",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now,
Posts = new List<Post>()
{
new Post()
{
Id = ,
BlogId = ,
Name = "EF Core TrackGraph",
CreatedTime = DateTime.Now,
ModifiedTime = DateTime.Now
}
}
}; var dbBlog = dbContext.Blogs
.AsNoTracking()
.Include(d => d.Posts).FirstOrDefault(d => d.Id == );
dbBlog = newBlog;
dbContext.Update(dbBlog);
var result = dbContext.SaveChanges();

说了这么多在EF Core中对于指定更新列不是太友好,当属性过多利用手动赋值就太麻烦,应该保留EF 6.x中利用CurrntValues对导航属性也进行直接更新岂不更好,如果调用Update方法将当前实体与快照中的实体比较指定更新列应该才是最佳方案。

Include....ThenInclude加载导航属性是否为最佳方案呢?

我们看如下三个示例实体

    public class A
{
public int Id { get; set; }
public ICollection<B> Bs { get; set; }
} public class B
{
public int Id { get; set; }
public C C { get; set; }
} public class C
{
public int Id { get; set; }
}

此时我们来查询A并通过显式加载B和C,如下:

            var dbContext = new EFCoreDbContext();
var As = dbContext.As.Include(d => d.Bs).ThenInclude(d => d.C).ToList();

大部分查询我们都会进行如上查询,但是我们是否思考是上述是否为最佳方案呢?或者性能更好呢?我也不知道,我也只是纯属猜测,因为要是我们进行如下加载数据呢?

        static void IncludeLoadCollection(EFCoreDbContext dbContext, object obj)
{
var entityEntry = dbContext.Entry(obj);
foreach (var collection in entityEntry.Collections)
{
if (collection.IsLoaded)
{
continue;
} collection.Load(); if (collection.CurrentValue != null)
{
foreach (var child in collection.CurrentValue)
{
IncludeLoadCollection(dbContext, child);
}
}
}
}
           var dbContext = new EFCoreDbContext();

            var a = dbContext.As.FirstOrDefault();
IncludeLoadCollection(dbContext, a);

如上代码未经测试,只是作为个人思考而给,您看到后私下可自行测试对比上述方案和通过Include....ThenInclude哪种方案更好呢?本文稍微讲解了下个人认为EF Core对于指定更新没有一个恰当的方式除了手动更新列外,当然字段太多,大部分情况下都会借助AutoMapper等进行DTO。

出版购买通知

现京东和淘宝上可正式预售购买《你必须掌握的EntityFramework 6.x与Core 2.0》书籍,我博客右上方也给了一个购买链接,让各位久等了。感谢各位同行一直以来的大力支持,同时也再次感谢博客园这个大平台,给了我机会去分享技术,我对EF既谈不上精通更谈不上不专家只不过是平时私下喜欢研究罢了,书中大部分都是我个人的理解,同时技术更新迭代太快,我也一直在追逐中而非停滞不前,我相信:无论出身环境怎样,自身天赋如何,笃定都可以通过自身的努力来改变并且成长。

EntityFramework Core指定更新导航属性了解一下?的更多相关文章

  1. 关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明

    一.首先了解下Entity Framework 自动关联查询: Entity Framework 自动关联查询,有三种方法:Lazy Loading(延迟加载),Eager Loading(预先加载) ...

  2. ef 更新导航属性

    总之,要让所有的东西,都被DbContext管理状态 1.查出来,改了,再提交 2.new 出来,attach,再改,再提交 以上两种都较好理解 3.new出来,改了,再attach,在改状态,再提交 ...

  3. EntityFramework Core 3多次Include导致查询性能低之解决方案

    前言 上述我们简单讲解了几个小问题,这节我们再来看看如标题EF Core中多次Include导致出现性能的问题,废话少说,直接开门见山. EntityFramework Core 3多次Include ...

  4. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

  5. EntityFramework Core饥饿加载忽略导航属性问题

    前言 .NET Core项目利用EntityFramework Core作为数据访问层一直在进行中,一直没有过多的去关注背后生成的SQL语句,然后老大捞出日志文件一看,恩,有问题了,所以本文产生了,也 ...

  6. EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public?

    前言 不知我们是否思考过一个问题,在关系映射中对于导航属性的访问修饰符是否一定必须为public呢?如果从未想过这个问题,那么我们接下来来探讨这个问题. EF 6.x和EF Core 何种情况下必须配 ...

  7. 【ASP.NET Core】EF Core - “导航属性”

    “导航属性”是实体框架用得算是比较频繁的概念. 首先,它是类型成员,其次,他是属性,这不是 F 话,而是明确它的本质.那么,什么场景下会用到导航属性呢?重点就落在“导航”一词上了,当实体 A 需要引用 ...

  8. EF Core反向导航属性解决多对一关系

    多对一是一种很常见的关系,例如:一个班级有一个学生集合属性,同时,班级有班长.语文课代表.数学课代表等单个学生属性,如果定义2个实体类,班级SchoolClass和学生Student,那么,班级Sch ...

  9. C# 数据操作系列 - 7. EF Core 导航属性配置

    在上一篇,大概介绍了Entity Framework Core关于关系映射的逻辑.在上一篇中留下了EF的外键映射没有说,也就是一对一,一对多,多对一,多对多的关系等.这一篇将为大家细细分析一下,如何设 ...

随机推荐

  1. 抽象类(abstract class)与接口(interface)的异同

    抽象类:如果一个类中包含抽象方法,那么这个类就是抽象类.在Java语言中,可以通过把类或类中的某些方法声明为abstract(abstract只能修饰类或方法,不能修饰属性)来表示一个类是抽象类. 接 ...

  2. Math类中round、ceil和floor方法的功能

    Java中的Math工具类用来完成除+.-.*./.%等基本运算以外的复杂运算,位于java.lang包下,Math类的构造器全是私有的(private),因此无法创建Math类的对象,Math类的方 ...

  3. 【源码学习】redux-thunk

    阅读 redux 源码之后,想要加深一下对中间件的理解,于是选择 redux-thunk(2.3.0)这个源码只有十几行的中间件. 之前 redux 的学习笔记 https://www.cnblogs ...

  4. pandas列合并为一行

    将dataframe利用pandas列合并为一行,类似于sql的GROUP_CONCAT函数.例如如下dataframe id_part pred pred_class v_id 0 d 0 0.12 ...

  5. Python爬虫入门教程 47-100 mitmproxy安装与安卓模拟器的配合使用-手机APP爬虫部分

    1. 准备下载软件 介绍一款爬虫辅助工具mitmproxy ,mitmproxy 就是用于MITM的proxy,MITM中间人攻击.说白了就是服务器和客户机中间通讯多增加了一层.跟Fiddler和Ch ...

  6. UmengShareDemo【友盟分享SDK集成,基于V6.9.3版本】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这里简单记录下友盟分享SDK集成的步骤. 如果想要使用自定义分享对话框实现,请参考<ShareDialogDemo[分享对话框 ...

  7. EXPLAIN 命令详解

    在工作中,我们用于捕捉性能问题最常用的就是打开慢查询,定位执行效率差的SQL,那么当我们定位到一个SQL以后还不算完事,我们还需要知道该SQL的执行计划,比如是全表扫描,还是索引扫描,这些都需要通过E ...

  8. .Net Core Web Api 上传女朋友的照片到微软云Azure Storage

    前言 实现一个Web Api,把女朋友照片保存到Azure云的storage里. Image Upload Api 在对应的Api Controller里,加上attribute: [Consumes ...

  9. Java基础系列-equals方法和hashCode方法

    原创文章,转载请标注出处:<Java基础系列-equals方法和hashCode方法> 概述         equals方法和hashCode方法都是有Object类定义的. publi ...

  10. Centos7 Jenkins日志过大

    df 查看 占用 [root@instance-ncwnnt0e /]# df Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs ...