EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

环境说明:EntityFramework 6.1.3和.Net Framework4.5
性能注意事项:https://msdn.microsoft.com/zh-cn/library/cc853327.aspx
比较精髓的一点:查询执行的各个阶段中的准备查询,每个唯一查询一次。包括编写查询命令、基于模型和映射元数据生成命令树和定义所返回数据的形状的成本。 因为实体 SQL查询命令和 LINQ 查询现已缓存,所以,以后执行相同查询所需的时间较少。 
如果有缓存的话,那么查询命令转成sql语句的性能会进一步提高,是不是ORM的效率更接近Ado.Net了呢?

性能注意点:此处参考了 http://www.cnblogs.com/jake1/archive/2013/04/25/3043664.html
a.在数据库里面分页
b.延迟加载要合理使用
c.需要连表的地方要连表查询
d.查询数据库的次数和发出的sql语句的数量和长度
e.NoTracking的使用

表ContactInfo,GroupInfo说明:

CREATE TABLE [dbo].[ContactInfo](

    [ID] [int] IDENTITY(1,1) NOT NULL,

    [ContactId] [nvarchar](128) NOT NULL,

    [IsDelete] [int] NOT NULL,

    [Account] [nvarchar](64) NOT NULL,

    [ContactName] [nvarchar](50) NOT NULL,

    [CommonMobile] [nvarchar](50) NULL,

    [HeadPortrait] [nvarchar](256) NULL,

    [AttFile] [nvarchar](256) NULL,

    [GroupId] [int] NULL,

 CONSTRAINT [PK_ContactInfo] PRIMARY KEY CLUSTERED 

(

    [ID] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]


CREATE TABLE [dbo].[GroupInfo](

    [GroupId] [int] IDENTITY(1,1) NOT NULL,

    [GroupName] [nvarchar](300) NOT NULL,

 CONSTRAINT [PK_GroupInfo] PRIMARY KEY CLUSTERED 

(

    [GroupId] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]


1.0 分页查询

c#语句:

var db = new PhoneBookEntities();
db.GroupInfo.Where(c => c.GroupName.Length>=2).OrderByDescending(c => c.GroupId).Skip(2).Take(3).ToArray();

sql语句:


SELECT TOP (3) 
[Filter1].[GroupId] AS [GroupId], 
[Filter1].[GroupName] AS [GroupName]FROM ( SELECT [Extent1].[GroupId] AS [GroupId], [Extent1].[GroupName] AS [GroupName], 
row_number() OVER (ORDER BY [Extent1].[GroupId] DESC) AS [row_number]FROM [dbo].[GroupInfo] AS [Extent1]WHERE (LEN([Extent1].[GroupName])) >= 2) AS [Filter1]WHERE [Filter1].[row_number] > 2ORDER BY [Filter1].[GroupId] DESC

 

2.0 FirstOrDefault,First

c#语句:

var db = new PhoneBookEntities();
db.GroupInfo.FirstOrDefault(c => c.GroupId == 1);

sql语句:

SELECT TOP (1) 
[Extent1].[GroupId] AS [GroupId], 
[Extent1].[GroupName] AS [GroupName]FROM [dbo].[GroupInfo] AS [Extent1]WHERE 1 = [Extent1].[GroupId]

 

延迟加载:

var db = new PhoneBookEntities();

var ci = db.ContactInfo.FirstOrDefault(c => c.ID == 9);

/* 此时产生的sql:*/


SELECT TOP (1) 
[Extent1].[ID] AS [ID], 
[Extent1].[ContactId] AS [ContactId], 
[Extent1].[IsDelete] AS [IsDelete], 
[Extent1].[Account] AS [Account], 
[Extent1].[ContactName] AS [ContactName], 
[Extent1].[CommonMobile] AS [CommonMobile], 
[Extent1].[HeadPortrait] AS [HeadPortrait], 
[Extent1].[AttFile] AS [AttFile], 
[Extent1].[GroupId] AS [GroupId]FROM [dbo].[ContactInfo] AS [Extent1]WHERE 9 = [Extent1].[ID] 


var gn= ci.GroupInfo.GroupName;

/* (运行到此行c#代码才会)产生sql:*/

exec sp_executesql N'SELECT 
[Extent1].[GroupId] AS [GroupId], 
[Extent1].[GroupName] AS [GroupName]
FROM [dbo].[GroupInfo] AS [Extent1]
WHERE [Extent1].[GroupId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

如果是一条数据,用延迟加载是OK的.如果上面查询有多条如10条结果,每条结果都使用到GroupInfo属性,那么一共会有11条sql请求.效率低.应该使用连表,一条sql搞定.写法如下.

第一种写法 Join:

那如果是多条数据,应使用预加载.
c#语句:


var db = new PhoneBookEntities();

var ci = db.ContactInfo.Where(c => c.ID >3).Join(db.GroupInfo,c=>c.GroupId,g=>g.GroupId,(c,g)=>new{c.ContactName,g.GroupName});

foreach (var item in ci) {MessageBox.Show(item.ContactName + "->" + item.GroupName); }


sql语句:


SELECT [Extent1].[ID] AS [ID], 
[Extent1].[ContactName] AS [ContactName], 
[Extent2].[GroupName] AS [GroupName]FROM [dbo].[ContactInfo] AS [Extent1]INNER JOIN [dbo].[GroupInfo] AS [Extent2] ON [Extent1].[GroupId] = [Extent2].[GroupId]WHERE [Extent1].[ID] > 3


说明:GroupJoin的用法,和Join使用类似.区别在于第四个参数resultSelector.

Join的第四个参数是 Func<ContactInfo,GroupInfo,anonymous type>.
GroupJoin的第四个参数是 Func<ContactInfo,IEnumerable<GroupInfo>,anonymous type>.
使用场景:联系人和他的好友.联系人一张表,好友关系一张表.联系人表和好友关系表做连接,查出多个联系人数据(包含他的好友),就应该使用GroupJoin.
简单说:
public partial class ContactInfo
{
public int ID { get; set; } 
public string ContactName { get; set; } 
public Nullable<int> GroupId { get; set; } 
public virtual GroupInfo GroupInfo { get; set; }
}
ContactInfo和GroupInfo一对一,该用Join;
如果是这种情况(仅仅是假设)
public partial class ContactInfo
{
public int ID { get; set; } 
public string ContactName { get; set; } 
public Nullable<int> GroupId { get; set; } 
public virtual List<GroupInfo> GroupInfo { get; set; }
}
ContactInfo和GroupInfo一对多,该用GroupJoin;

第二种写法 Include:

注意:数据库设计ContactInfo,GroupInfo 要有主外键关系.
c#语句:


var db = new PhoneBookEntities();var ci = db.ContactInfo.Include("GroupInfo").Where(c => c.ID > 3).Select(c => new { c.ContactName, c.GroupInfo.GroupName }); //或者 Include(c=>c.GroupInfo)foreach (var item in ci)
{MessageBox.Show(item.ContactName + "->" + item.GroupName);
}


sql语句:


SELECT [Extent1].[ID] AS [ID], 
[Extent1].[ContactName] AS [ContactName], 
[Extent2].[GroupName] AS [GroupName]FROM [dbo].[ContactInfo] AS [Extent1]LEFT OUTER JOIN [dbo].[GroupInfo] AS [Extent2] ON [Extent1].[GroupId] = [Extent2].[GroupId]WHERE [Extent1].[ID] > 3


3.0 Add

c#语句:

var db = new PhoneBookEntities();var giModel = new GroupInfo();
giModel.GroupName = "Test";
db.GroupInfo.Add(giModel);
db.SaveChanges();//Add方法之后,会把数据库表记录中的GroupId给giModel.

sql语句:

exec sp_executesql N'INSERT [dbo].[GroupInfo]([GroupName])
VALUES (@0)
SELECT [GroupId]
FROM [dbo].[GroupInfo]
WHERE @@ROWCOUNT > 0 AND [GroupId] = scope_identity()',N'@0 nvarchar(300)',@0=N'Test'

 

4.0 AddRange

c#语句:

var db = new PhoneBookEntities();var gi = new GroupInfo[] { new GroupInfo() { GroupName = "g1" }, new GroupInfo() { GroupName = "g2" }, new GroupInfo() { GroupName = "g3" }, };
db.GroupInfo.AddRange(gi);
db.SaveChanges();

sql语句:


exec sp_executesql N'INSERT [dbo].[GroupInfo]([GroupName])
VALUES (@0)
SELECT [GroupId]
FROM [dbo].[GroupInfo]
WHERE @@ROWCOUNT > 0 AND [GroupId] = scope_identity()',N'@0 nvarchar(300)',@0=N'g1'exec sp_executesql N'INSERT [dbo].[GroupInfo]([GroupName])
VALUES (@0)
SELECT [GroupId]
FROM [dbo].[GroupInfo]
WHERE @@ROWCOUNT > 0 AND [GroupId] = scope_identity()',N'@0 nvarchar(300)',@0=N'g2'...


共执行3次.但是连接只打开关闭了1次.

5.0 Remove

c#语句:

var db = new PhoneBookEntities();var ci= db.GroupInfo.FirstOrDefault(c => c.GroupId == 214);
db.GroupInfo.Remove(ci);
db.SaveChanges();

sql语句:


SELECT TOP (1) 
[Extent1].[GroupId] AS [GroupId], 
[Extent1].[GroupName] AS [GroupName]FROM [dbo].[GroupInfo] AS [Extent1]WHERE 214 = [Extent1].[GroupId]exec sp_executesql N'DELETE [dbo].[GroupInfo]
WHERE ([GroupId] = @0)',N'@0 int',@0=214

感觉繁琐啦?解决方案,1,自己定义方法;2,引用EntityFramework.Extended

来源https://www.nuget.org/packages/EntityFramework.Extended/或者在当前项目里,引用点击右键,选择管理NuGet程序包,联机搜索并下载.
引用之后操作就简单了.

c#语句:

var db = new PhoneBookEntities(); 
db.GroupInfo.Delete(c => c.GroupName == "Test");//过时的方法db.GroupInfo.Where(c => c.GroupName == "Test").Delete();//如果查到的记录数为0,也不报错.上边的先查 FirstOrDefault 后删 Remove,你猜猜报错吗db.SaveChanges();

 

sql语句:

DELETE [dbo].[GroupInfo]FROM [dbo].[GroupInfo] AS j0 INNER JOIN (SELECT [Extent1].[GroupId] AS [GroupId]FROM [dbo].[GroupInfo] AS [Extent1]WHERE N'Test' = [Extent1].[GroupName]) AS j1 ON (j0.[GroupId] = j1.[GroupId])


一条sql语句搞定删除.

6.0 更新操作


基于EntityFramework.Extended的更新操作.
c#语句:

db.GroupInfo.Where(c => c.GroupName.Contains("g")).Update(c => new GroupInfo() { GroupName = c.GroupName+"!"});//此处没有db.SaveChanges();,一样执行了操作.

sql语句:


UPDATE [dbo].[GroupInfo] SET [GroupName] = [GroupName] + N'!' FROM [dbo].[GroupInfo] AS j0 INNER JOIN (SELECT [Extent1].[GroupId] AS [GroupId]FROM [dbo].[GroupInfo] AS [Extent1]WHERE [Extent1].[GroupName] LIKE N'%g%') AS j1 ON (j0.[GroupId] = j1.[GroupId])


也是一条sql语句搞定批量修改.

(注意:update语句中只set了GroupName字段;
不用EntityFramework.Extended,用EF的先查后改,sql语句也是只set了GroupName字段.
更特殊的情况,以下例子:

var gi = db.GroupInfo.FirstOrDefault(c => c.GroupId == 219 );//此条记录的GroupName为"Test"gi.GroupName = "Test";
db.SaveChanges();

EF会自动优化,最终结果只有一个select语句,而没有update语句. 此处细节,赞!

对比NHibernate 4,以下两行代码产生的sql语句会set Product表的[所有]字段
var pl = session.Query<Product>().FirstOrDefault(c => c.Name == "cnblogs");
pl.Name = "ICE";
)
如果先查出来要更改的数据,再修改.也是可以的. 但是从效率考虑,不管是c#写法还是产生的sql语句,基于EntityFramework.Extended的更新操作更优.

7.0 EntityFramework.Extended中Future的使用

c#语句:

var db = new PhoneBookEntities();var fci = db.ContactInfo.Where(c => c.ID > 1).FutureFirstOrDefault();var fgi = db.GroupInfo.Where(c => c.GroupId > 2).FutureFirstOrDefault();
ContactInfo ci= fci.Value;
GroupInfo gi = fgi.Value;

//采用Future的写法,不会立即查询数据库.只要调用结果的任意一个 .ToList,.ToArray或者.Value ,才会查数据库.并且只发一个请求(Query #1 + Query #2 拼接好后发给数据库,一起执行语句).

sql语句:

-- Query #1SELECT TOP (1) 
[Extent1].[ID] AS [ID], 
[Extent1].[ContactId] AS [ContactId], 
[Extent1].[IsDelete] AS [IsDelete], 
[Extent1].[Account] AS [Account], 
[Extent1].[ContactName] AS [ContactName], 
[Extent1].[CommonMobile] AS [CommonMobile], 
[Extent1].[HeadPortrait] AS [HeadPortrait], 
[Extent1].[AttFile] AS [AttFile], 
[Extent1].[GroupId] AS [GroupId]FROM [dbo].[ContactInfo] AS [Extent1]WHERE [Extent1].[ID] > 1;-- Query #2SELECT TOP (1) 
[Extent1].[GroupId] AS [GroupId], 
[Extent1].[GroupName] AS [GroupName]FROM [dbo].[GroupInfo] AS [Extent1]WHERE [Extent1].[GroupId] > 2;


标注:EntityFramework.Extended相关部分参考了 顾振印的博文: http://www.cnblogs.com/GuZhenYin/p/5482288.html

8.0 AsNoTracking

c#语句:

var db = new PhoneBookEntities();

var gi = db.GroupInfo.FirstOrDefault(c => c.GroupId == 219); MessageBox.Show(db.Entry(gi).State.ToString());//Unchanged

var giAnk = db.GroupInfo.AsNoTracking().FirstOrDefault(c => c.GroupId == 219); MessageBox.Show(db.Entry(giAnk).State.ToString());//Detached

相关文章:

原文地址:http://www.cnblogs.com/DKnight/p/5601680.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三个水桶(看了三遍,想了五遍!)

转载至&#xff1a;微信公众号&#xff1a; 创业励志网 一 有位木匠砍了一树&#xff0c;把它做了三个木桶。 一个装粪&#xff0c;就叫粪桶&#xff0c;众人躲着&#xff1b; 一个装水&#xff0c;就叫水桶&#xff0c;众人用着&#xff1b; 一个装酒&#xff0c;就叫酒桶&…

nginx解析php失败,为什么nginx不能解析php?

只运行过这些代码yum install -y vim wget zip unzip git httpd php php-mysql php-odbc php-ldap php-gd php-mbstring php-xml php-xml-rpc php-bcmath libjpeg* mariadb ;rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarc…

.NET Core amp; ASP.NET Core 1.0在Redhat峰会上正式发布

众所周知&#xff0c;Red Hat和微软正在努力使.NET Core成为Red Hat企业版Linux (RHEL)系统上的一流开发平台选项。这个团队已经一起工作好几个月了,RHEL对.NET有许多需求。今天在RedHat 峰会DevNation 上宣布了.NET Core & ASP.NET Core 1.0 RTM。Red Hat有一个新的关于在…

任务调度(三)——Timer的替代品ScheduledExecutorService简介

转载自 任务调度(三)——Timer的替代品ScheduledExecutorService简介先前的两篇博文《任务调度(一)——jdk自带的Timer》和《任务调度(二)——jdk自带的Timer 动态修改任务执行计划》中&#xff0c;简单介绍了一下Timer&#xff0c;可以实现几本的功能&#xff0c;但是在多线程…

jquery实现动态五角星评分

先上代码&#xff0c;最后附属上我的实现思路&#xff0c;新手做的bug多&#xff0c;大牛勿喷&#xff1a;请看代码&#xff1a; ☆☆☆☆☆<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-trans…

php中时间轴,PHP时间轴函数

26 04 2013PHP时间轴函数Yinchiang | 0我们会经常看见现在许多网站的留言或者评论的时间变得十分有趣&#xff0c;刚刚、3分钟前、1天前等等人性化的时间轴好吧&#xff0c;我承认这个函数是转载的&#xff0c;部分按照自己的需求修改了一点点。/*** 时间轴函数&#xff0c;单位…

开源Asp.Net Core小型社区系统

前言 盼星星盼月亮&#xff0c;Asp.Net Core终于发布啦&#xff01;&#xff01; Asp.Net发布时我还在上初中&#xff0c;没有赶上。但是Asp.Net Core我从beta版本便一直关注。最初项目名叫Asp.Net VNext&#xff0c;然后改名叫Asp.Net 5。最煎熬的是RC1发布后&#xff0c;官方…

Java多线程干货系列(1):Java多线程基础

转载自 Java多线程干货系列&#xff08;1&#xff09;&#xff1a;Java多线程基础前言 多线程并发编程是Java编程中重要的一块内容&#xff0c;也是面试重点覆盖区域&#xff0c;所以学好多线程并发编程对我们来说极其重要&#xff0c;下面跟我一起开启本次的学习之旅吧。 正文…

php accesscontrolalloworigin,设置Access-Control-Allow-Origin实现跨域访问

这篇文章主要介绍了Ajax 设置Access-Control-Allow-Origin实现跨域访问,非常不错&#xff0c;具有参考借鉴价值&#xff0c;需要的朋友可以参考下ajax跨域访问是一个老问题了&#xff0c;解决方法很多&#xff0c;比较常用的是JSONP方法&#xff0c;JSONP方法是一种非官方方法&…

.NET Core:面向未来的开源跨平台开发技术

作为一种全新的开源和跨平台的开发平台&#xff0c;.NET Core 历经两年多的开发&#xff0c;终于在于2016年6月27日针对所有主流服务器和桌面操作系统发布 1.0 RTM 版本。.NET Core 是一种通用开发平台&#xff0c;它包含了自动内存管理和现代化高级开发语言等重要特性&#xf…

Sublime Text 3 快捷键总结(拿走)

以下是个人总结不完全的快捷键总汇&#xff0c;祝愿各位顺利解放自己的鼠标。选择类CtrlD 选中光标所占的文本&#xff0c;继续操作则会选中下一个相同的文本。AltF3 选中文本按下快捷键&#xff0c;即可一次性选择全部的相同文本进行同时编辑。举个栗子&#xff1a;快速选中并…

Java多线程学习

转载自 Java多线程学习本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。在这之前&#xff0c;首先让我们来了解下在操作系统中进程和线程的区别&#xff1a;进程&#xff1a;每个进程都有独立的代码和数据空间&#…

php面试心得,php面试题的总结

这篇文章介绍的内容是关于php面试题的总结&#xff0c;有着一定的参考价值&#xff0c;现在分享给大家&#xff0c;有需要的朋友可以参考一下1. 什么事面向对象&#xff1f;主要特征是什么&#xff1f;面向对象是程序的一种设计方式&#xff0c;它利于提高程序的重用性&#xf…

展望C# 7

译者&#xff1a;雪落无痕 xdj 目前的 C# 编译器&#xff08;即 Roslyn&#xff09;于 2014 年 4 月开源。目前不仅是编译器在 GitHub 上开发&#xff1b;语言的设计也是进行公开的讨论。 这允许感兴趣的各方了解语言下一个版本的样子。这篇文章概述了当前在设计语言新特性时的…

Java 线程池详解及实例代码

转载自 Java 线程池详解及实例代码这篇文章主要介绍了Java 线程池的相关资料,并符实例代码&#xff0c;帮助大家学习参考&#xff0c;需要的朋友可以参考下线程池的技术背景 在面向对象编程中&#xff0c;创建和销毁对象是很费时间的&#xff0c;因为创建一个对象要获取内存资…

jQuery最简单的留言功能^-^

先上代码&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml" xml:lang"en"> <h…

rocketmq java home,rocketmq 安装与配置以及遇到的问题

不废话&#xff0c;搞起双M 模式环境1&#xff0c;java-1.8这里有个问题&#xff0c;centos 安装yum install java-1.8 是只是安装的java 运行环境jre&#xff0c;还缺少开发包所以在编译的时候会有问题&#xff0c;使用yum install yum install java-1.8.0-openjdk-devel* 这…

聊聊并发(八)——Fork/Join框架介绍

转载自 聊聊并发&#xff08;八&#xff09;——Fork/Join框架介绍1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架&#xff0c; 是一个把大任务分割成若干个小任务&#xff0c;最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过F…

Mads Torgersen介绍C# 7及后续版本新特性

在QCon纽约2016大会上&#xff0c;C#项目经理Mads Torgersen介绍了即将到来的C# 7。他还简单地阐述了C#的演化过程&#xff0c;并展示了部分正在开发的未来版本特性。 近年来&#xff0c;云和分布式系统的出现使开发人员面临着新的挑战。开发人员需要进步&#xff0c;语言也要随…

Java的不同进制输出,[DanoR][Java小码][进制转换::将double转换为不同进制后用String输出]...

功能简述进制转换输入: 一个数(double),目标进制(int)和小数的保留位数(int)输出: 相应进制的表示方式(String)参数说明double number; //将要被转换的数int ary; //目标进制int accuracy; //指定小数保留的位数特性支持小数转换例0: (5.20, 8, 4) --> 5.146314631463146315…