前言

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

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. Get Total Sum Using Multithread Programming

    Write a program that finds the sum value in an array of ints using 4 threads. You may assume in your ...

  2. 注解ConfigurationProperties注入yml配置文件中的数据

    在使用SpringBoot开发中需要将一些配置参数放在yml文件中定义,再通过Java类来引入这些配置参数 SpringBoot提供了一些注解来实现这个功能 ConfigurationProperti ...

  3. FFmpeg开发实战(六):使用 FFmpeg 将YUV数据编码为视频文件

    本文中实现的一个小功能是把一个YUV原始视频数据(时间序列图像)经过h264编码为视频码流,然后在使用mp4封装格式封装. 编码&封装的流程图如下: 使用ffmpeg编码流程: 1.首先使用a ...

  4. Spring Cloud微服务系列文,服务调用框架Feign

    之前博文的案例中,我们是通过RestTemplate来调用服务,而Feign框架则在此基础上做了一层封装,比如,可以通过注解等方式来绑定参数,或者以声明的方式来指定请求返回类型是JSON.    这种 ...

  5. 【Android Studio安装部署系列】三十六、Android studio3.2使用过程中注意事项

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio升级到3.2之后,运行旧项目的时候出现了各种情况,特此记录下. 一.打包选项多了,一般情况下选择APK即 ...

  6. ShareIntentUtil【调用系统自带的分享的工具类】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 根据参考资料的文章,整理了调用系统自带分享的工具类(实现了适配7.0FileProvider的功能),需要搭配<Android ...

  7. Vmware虚拟机中CentOS7与Docker安装图文教程

    1.安装VMware 下载一个软件安装: 2.新建一个虚拟机 等待自动安装完成 配置系统语言: 配置系统时间: 配置系统键盘: 语言支持: 默认自动使用安装源: 配置软件环境,需要及时添加的软件,这里 ...

  8. C#的dapper使用

    Dapper是一款轻量级ORM工具(Github).如果你在小的项目中,使用Entity Framework.NHibernate 来处理大数据访问及关系映射,未免有点杀鸡用牛刀.你又觉得ORM省时省 ...

  9. C# 读取PDF多级书签

    在PDF中,书签作为一种导航的有效工具,能帮助我们快速地定位到文档中的指定段落.同时,书签也能让人对文档结构一目了然,在某种程度上也可作为目录使用.对于C#操作PDF中的书签,在上一篇文章中介绍了具体 ...

  10. Spring MVC(四)文件上传

    文件上传步骤 1.写一个文件上传的页面 2.写一个文件上传的控制器 注意: 1.method="post" 2.enctype="multipart/form-data& ...