EF6学习笔记八:实体状态以及实现IEnumerable和实现IQueryable接口数据集查询方法的支持差异...

本文主要是介绍EF6学习笔记八:实体状态以及实现IEnumerable和实现IQueryable接口数据集查询方法的支持差异...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要专业系统地学习EF前往《你必须掌握的Entity Framework 6.x与Core 2.0》这本书的作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/

实体状态

通过EF上下文与数据库交互的实体,都会被EF跟踪,并且实体会被分配状态。

我们在添加修改删除数据的时候没有注意到这个实体状态,是因为在我们调用Add()、Remove()这些方法时,其实就是对实体的状态进行改变

实体状态都有五种,在System.Data.Entity命名空间下的EntityState类里面

public enum EntityState{Detached = 1,Unchanged = 2,Added = 4,Deleted = 8,Modified = 16}
View Code

 

1.Added状态针对添加操作,当标记为此状态时,表明实体被上下文所追踪但是不存在与数据库中

      什么意思?就是在调用SaveChanges时,如果发现有实体是这个状态,就会将该实体添加到数据库中

2.Unchanged  实体被上下文追踪,但是存在于数据库中的值未发生改变

      这说的是,你从数据库中查出的数据就是Unchanged状态,可不是值没有改变嘛?可不就是被跟踪了吗?

3.Modified   实体被上下文跟踪并存在于数据库中,同时部分或者所有属性值已经被更改

      这个还是好理解的,不过要注意,这些状态都说了,要被上下文追踪。

4.Deleted   实体被上下文跟踪并存在于数据库中,当标记为Deleted状态时,SaveChanges时数据将在数据库中被删除

5.Detached  这个就是表示没有被上下文追踪,只有通过上下文得到的实体对象才会有被跟踪,才会有其他状态,否则就是Detached

我们来把各种被操作的实体的状态打印出来看看,查看实体状态,用Entry()方法

我们现在凭空new 一个对象

using (EFDbContext db = new EFDbContext()){Book book1 = new Book { Name = "演员自我修养", Number = "NO8973424", Price = 21.5m };var state = db.Entry(book1).State;Console.WriteLine(state);  //  Detached}
View Code

 

当我们调用Add方法,实体状态变为Added

Book book1 = new Book { Name = "演员自我修养", Number = "NO8973424", Price = 21.5m };db.Books.Add(book1);var state = db.Entry(book1).State;Console.WriteLine(state);  //  Added
View Code

 

然后将这个实体添加到数据库,然后查询出来,这个查询出来的实体状态为Unchanged

Book book1 = new Book { Name = "演员自我修养", Number = "NO8973424", Price = 21.5m };db.Books.Add(book1);db.SaveChanges();var state = db.Entry(book1).State;Console.WriteLine(state);  //  Unchanged
View Code

 

让我想不到的是,我不用查询,直接查看他的状态就是Unchanged,有点神奇

我们查询出一个实体,然后修改某个属性值,状态变为Modified

var res = db.Books.ToList().FirstOrDefault();res.Name = "新华字典";var state = db.Entry(res).State;Console.WriteLine(state);  //  Modified
View Code

 

我们调用Remove方法,实体状态变为Deleted。我刚刚还为Unchanged状态感到神奇呢,现在看来我居然只有通过这种方式来获得Deleted状态

var res = db.Books.ToList().FirstOrDefault();db.Books.Remove(res);var state = db.Entry(res).State;Console.WriteLine(state);  //  Deleted
View Code

 

上下文没有提供Update方法,所以我们要通过更改实体状态的方式来更新数据

var res = db.Books.ToList().FirstOrDefault();res.Name = "新华字典";db.Entry(res).State = System.Data.Entity.EntityState.Modified;db.SaveChanges();
View Code

 

关于实体状态就先浅尝辄止了

实现IEnumerable<>接口和IQueryable<>接口数据集支持查询方法的差异

我在学LINQ(语言集成查询)时对这两个接口稍微有点了解,之后看别人的博客,详解IQueryable<>接口,我看不太明白,很气馁

LINQ是什么,他是想对查询语法做一个统一,我们在数据库中查询数据要写SQL语句,查询XML用DOM操作,那能不能来个统一的方式,不要让我去学习那么多的查询语句了,那么LINQ就来了

写LINQ有两种方法,一个是写查询语句,像什么from a in list  select a;这样的,还一个就是调用方法,像Where()、Select()……

这两种方式没什么区别,只不过一些聚合查询必须得调用方法才行,大部分的查询语句和方法都能来

还有一点,LINQ里面有延迟加载,聚合查询会立即执行,官网上面写了有,什么方法会立即执行查询

LINQ的那些查询方法都是扩展在IEnumberable类上的,所以我们也可以通过扩展这个类来扩展LINQ

我来说一下IEnumberable<>和IQueryable<>这两个接口,查询内存中的数据都是实现的IEnumberable接口,查询远程数据是实现的IQueryable<>接口

List<int> list = new List<int> { 12, 32, 34, 55, 66 };list.Where();var res = db.Books.Where();
View Code

 

他们之间很多方法都匹配,但是有一些方法不行,上面的两个Where方法不是一样的,一个返回的是IEnumberable,一个返回的IQueryable

Last 和LastOrDefault

这两个方法在IQueryable中不支持,我也就搞不明白了,算了,反正这两方法我真是一次都没用过

当我对上下文的数据集调用LastOrDefault方法时,报错,NotSupportedException  不支持异常

System.NotSupportedException: LINQ to Entities does not recognize the method '_2019011402.Entity.Book LastOrDefault[Book](System.Linq.IQueryable`1[_2019011402.Entity.Book])' method, and this method cannot be translated into a store expression.

Contains方法

Book book1 = new Book { Id = Guid.NewGuid().ToString(), Name = "自我修养", Price = 30m };Book book2 = new Book { Id = Guid.NewGuid().ToString(), Name = "新华字典", Price = 30m };Book book3 = new Book { Id = Guid.NewGuid().ToString(), Name = "天国之秋", Price = 30m };List<Book> bookList = new List<Book>();bookList.Add(book1);bookList.Add(book2);bookList.Add(book3);bool boo = bookList.Contains(book1);  Console.WriteLine(boo);  //  Truevar frist = db.Books.FirstOrDefault();db.Books.Contains(frist);  //  报错 NotSupportedException
View Code

 

我对内存中的数据进行查询,和远程查询数据库中的数据,得到上面的结果。 EF不支持Contains方法,虽然这个方法我几乎不使用,感觉甚至都不想去了解这些差异的东西了。但是刚刚想到,万一我使用到了呢?然后我发现在IEnumberable中是可以的,但是查询EF上下文的数据集为什么又不行呢?

然后我就只会怀疑是不是自己写错了,然后我能想到我怎么想都不知道错在哪里,然后独自抓耳挠腮,其实现在知道是系统的问题,那么就不会动不动就怀疑人生了。

但是如果你对上下文中的数据集进行Select(x=>x.Name)查询之后,得出的List<string>集合再调用Contains方法又是可以的,所以对于简答类型的集合可以,复杂类型的不行

var res = db.Books.Select(x => x.Name);var res2 = res.Contains("新华字典");  //  TrueConsole.WriteLine(res2);
View Code

 

Case和OfType

这两方法主要查询集合里面指定类型的数据

case方法主要针对基元类型进行查询(int、string……),总之相当不好用,它是全盘转换,类型不匹配,就抛出异常,这有什么用?可以判断一个集合中的数据是不是都是同一类型,但是现在都使用泛型集合List<T>,哪还使用List<object>

List<object> list = new List<object> { 12, 34, 35, "55", "33", true, false, 32.4 };var res = list.Cast<string>();Console.WriteLine(JsonConvert.SerializeObject(res)); //  报错 无法将System.Int32强制转换为System.String
View Code

 

OfType 就友好地多,满足条件才转换,上面的cast换成OfType得到的结果是:["55","33"]

OfType查询内存中的数据,对于基元类型和复杂类型都是Ok的

List<object> list3 = new List<object> { 12, 34, 35, "55", "33", true, false, 32.4 };var res3 = list3.OfType<string>();Console.WriteLine(JsonConvert.SerializeObject(res3));  //  ["55","33"]
Book book1 = new Book { Id = Guid.NewGuid().ToString(),Name = "西游记"};var teacher = new { Name="张老师",Salary = 4543.5};List<object> list = new List<object>();list.Add(book1);list.Add(teacher);var res = list.OfType<Book>();Console.WriteLine(JsonConvert.SerializeObject(res));//  [{"Name":"西游记","Number":null,"Price":0.0,"Id":"1c9d0a8a-b62b-40df-a995-409b828c3714","AddTime":"2019-01-14T22:53:15.5019894+08:00"}]
View Code

 

然后我们查询上下文中的数据集

var res2 = db.Books.Select(x => x.Name).OfType<string>();Console.WriteLine(JsonConvert.SerializeObject(res2));//  报错 NotSupportedException
View Code

 

这说明EF不支持OfType针对基元类型进行查询,但是,如果我们对数据集调用ToList()方法,再来看看

var res2 = db.Books.ToList().Select(x => x.Name).OfType<string>();Console.WriteLine(JsonConvert.SerializeObject(res2));  //  ["新华字典","演员自我修养"]
View Code

 

现在居然查出来了,为什么,这是因为ToList()方法,我们在没有使用ToList()方法之前,都是远程查询,然后调用ToList方法,数据被拿到内存里面来了,这中间变化就大了

ToList()把数据拿到了内存里面,所以就不会延迟查询了,他是对内存中的数据进行查询的,所以IEumberable<>和IQueryable之间是可以转换的,这个要相当注意

Skip方法

对上下文数据集使用Skip方法之前必须要排序,不然报错

var res = db.Books.Skip(1).ToList();
View Code

 

System.NotSupportedException: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.

但是对于内存中的数据集调用Skip方法之前,不排序就可以

Book book1 = new Book { Id = Guid.NewGuid().ToString(), Name = "自我修养", Price = 30m };Book book2 = new Book { Id = Guid.NewGuid().ToString(), Name = "新华字典", Price = 30m };Book book3 = new Book { Id = Guid.NewGuid().ToString(), Name = "天国之秋", Price = 30m };List<Book> bookList = new List<Book>();bookList.Add(book1);bookList.Add(book2);bookList.Add(book3);var res = bookList.Skip(1).ToList();Console.WriteLine(JsonConvert.SerializeObject(res));//  [{"Name":"新华字典","Number":null,"Price":30.0,"Id":"3b890089-5046-4aae-9a30-2d6bf97f2160","AddTime":"2019-01-14T23:23:33.2341685+08:00"},{"Name":"天国之秋","Number":null,"Price":30.0,"Id":"542fa82b-4a6a-41dd-97df-bb4876cdbc52","AddTime":"2019-01-14T23:23:33.2341685+08:00"}]
View Code

 

Take方法

如果单单调用Take方法,生成的SQL语句,使用的是SQL里面的TOP关键字

var res = db.Books.Take(2);Console.WriteLine(res);
View Code
SELECT TOP (2)[c].[Id] AS [Id],[c].[Name] AS [Name],[c].[Number] AS [Number],[c].[Price] AS [Price],[c].[AddTime] AS [AddTime]FROM [dbo].[Book] AS [c]
View Code

 

这里可以看到,我直接打印的查询语句,这就是延迟查询,上面的语句根本就没有执行查询,如果我调用ToList()方法就不一样了,打印出来的就直接是数据了

所以如果你没有调用那些导致立即执行查询的方法,那么就可以打印看看SQL语句是什么,就不用取跟踪查询EF生成的SQL语句了

然后我们对内存中的数据集单单调用Take方法看看

Book book1 = new Book { Id = Guid.NewGuid().ToString(), Name = "自我修养", Price = 30m };Book book2 = new Book { Id = Guid.NewGuid().ToString(), Name = "新华字典", Price = 30m };Book book3 = new Book { Id = Guid.NewGuid().ToString(), Name = "天国之秋", Price = 30m };List<Book> bookList = new List<Book>();bookList.Add(book1);bookList.Add(book2);bookList.Add(book3);var res = bookList.Take(2);Console.WriteLine(JsonConvert.SerializeObject(res));//  [{"Name":"自我修养","Number":null,"Price":30.0,"Id":"2b4b85c6-109a-485f-9e4f-95b4e5da2ee9","AddTime":"2019-01-14T23:38:07.5226753+08:00"},{"Name":"新华字典","Number":null,"Price":30.0,"Id":"b51e5e61-097b-4fe5-89ca-5283abd16332","AddTime":"2019-01-14T23:38:07.526798+08:00"}]
View Code

 

出来的就直接是数据了,对于内存中的数据集查询也就不用生成SQL语句了

Select投影转换为实体类型

针对内存中的数据集查询,没问题

Book book1 = new Book { Id = Guid.NewGuid().ToString(), Name = "自我修养", Price = 30m };Book book2 = new Book { Id = Guid.NewGuid().ToString(), Name = "新华字典", Price = 30m };Book book3 = new Book { Id = Guid.NewGuid().ToString(), Name = "天国之秋", Price = 30m };List<Book> bookList = new List<Book>();bookList.Add(book1);bookList.Add(book2);bookList.Add(book3);var res = bookList.Select(x => new Book{Name = x.Name});Console.WriteLine(JsonConvert.SerializeObject(res));//[{"Name":"自我修养","Number":null,"Price":0.0,"Id":"3f261e85-0bae-45e2-8b59-7694df8bf602","AddTime":"2019-01-14T23:43:01.8446418+08:00"},{"Name":"新华字典","Number":null,"Price":0.0,"Id":"9657f6c5-ce19-43ef-b86f-4a0db6c803de","AddTime":"2019-01-14T23:43:01.8748982+08:00"},{"Name":"天国之秋","Number":null,"Price":0.0,"Id":"a654a851-2f96-4934-9720-a2add7861061","AddTime":"2019-01-14T23:43:01.8748982+08:00"}]
View Code

 

但是针对上下文的数据集,报错 NotSupportedException

var res = db.Books.Select(x => new Book{Name = x.Name});Console.WriteLine(JsonConvert.SerializeObject(res));  //  报错 NotSupportedException
View Code

 

我们换成匿名类型,可以的

var res = db.Books.Select(x => new{Name = x.Name});Console.WriteLine(JsonConvert.SerializeObject(res)); //  [{"Name":"三国演义"},{"Name":"天国之秋"},{"Name":"新华字典"},{"Name":"堂吉诃德"},{"Name":"演员自我修养"},{"Name":"水浒传"},{"Name":"红楼梦过"}]
View Code

 

转载于:https://www.cnblogs.com/jinshan-go/p/10269731.html

这篇关于EF6学习笔记八:实体状态以及实现IEnumerable和实现IQueryable接口数据集查询方法的支持差异...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/581034

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;