大家都知道Linq既可以用来查询数据库对象(我这里指的是Entity FrameWork里的Model对象),也可以用来查询内存中的IEnumerable对象。

两者单独查询时都不会出现什么问题,不过混合在一起时(一般是用关键字来join连接),要注意的地方就多着了。

情形1:Linq to Object 连接(join) Linq to Entity

我们首先来看这段代码:(注意:Linq代码里是把内存中的数据代码,也就是Linq to object放在join前面,数据库的数据代码放在join后面)

List<MyObject> objectList = new List<MyObject>();
objectList.Add(new MyObject { Identity = , Name = "Jack", Age = });
objectList.Add(new MyObject { Identity = , Name = "Sam", Age = });
objectList.Add(new MyObject { Identity = , Name = "Lucy", Age = }); EntityRepository repository = new EntityRepository();
DbSet<Entity> entitySet = repository.Context.Set<Entity>(); var objectNames = (from ob in objectList
join en in entitySet
on ob.Identity equals en.SID
select ob.Name).ToList();

Entity是数据库表,有一个bigint型,名为SID字段,其他俩个为Name和Notes。上面的代码中是把Linq to Object放在前面,Linq to Entity 放在join中,编译运行顺利。

实际的查询数据库的语句为:

SELECT
[Extent1].[SID] AS [SID],
[Extent1].[Name] AS [Name],
[Extent1].[Notes] AS [Notes]
FROM [dbo].[Entity] AS [Extent1]

这里是整表查询。(可以打开Sql Server 2008 R2-->Performance Tools-->SQL Server Profiler, 来跟踪此语句)。

如果把以上代码改成select en.Name,仍然是整表查询。

如果是设计两个数据库表的查询,且最后是select 表中的某一列,则不可能是整表查询,而是单独查询了某一列;而这里把entity和object放在一起,就会涉及整表查询。此乃两者混合使用的第一弊端。

情形2: Linq to Entity 连接(join) Linq to Object

数据库的数据代码Linq to Entity在join前,内存中数据代码Linq to Object在join后。代码如下:

 var entityNames = (from en in entitySet
join ob in objectList
on en.SID equals ob.Identity
select en.Name).ToList();

好了,编译通过,运行时抛异常了。

Only Primitive types ('Such as Int32, string, and Guid') are supported in this context

中文意思是“无法创建类型为“项目名.MyObject”的常量值。此上下文仅支持基元类型(“例如 Int32、String 和 Guid”)"

看来在涉及这种操作时,我们内存中的数据还不能是非基元类型。List<MyObject> objectList = new List<MyObject>();

MyObject要为int32, string或者Guid,才能运行通过,并且不是整表查询,而是针对name列的单独查询。大家可以一试。

所以在这里给出大家一点建议:

在涉及到内存中的对象与EF里的对象混合查询时,如果内存中的对象不为基元类型,则先把其中的某个要参加匹配的变量查询出来,再拿着它与EF对象混合查询。

这样不仅不会出错,效率也高,且代码会两段写,也容易看清楚意思。

以上的代码这样,才是最佳的

IEnumerable<long> idList = objectList.Select(o => o.Identity);

var entityNames = (from en in entitySet
join id in idList
on en.SID equals id
select en.Name).ToList();

数据库查询语句如下:

SELECT
[Extent1].[Name] AS [Name]
FROM [dbo].[Entity] AS [Extent1]
INNER JOIN (SELECT
[UnionAll1].[C1] AS [C1]
FROM (SELECT
cast( as bigint) AS [C1]
FROM ( SELECT AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
cast( as bigint) AS [C1]
FROM ( SELECT AS X ) AS [SingleRowTable2]) AS [UnionAll1]
UNION ALL
SELECT
cast( as bigint) AS [C1]
FROM ( SELECT AS X ) AS [SingleRowTable3]) AS [UnionAll2] ON CAST( [Extent1].[SID] AS bigint) = [UnionAll2].[C1]

虽然里面的操作是麻烦了点,但是最后查询出来的东西却只有Name一个。相对而言,还是比较好的。

情形3:Linq to entities does not recognize the method 'Int32 get_item(int32)'

Linq to entities does not recognize the method 'Int32 get_item(int32)' method, and this method cannot be translated into a store expression

Linq to Entities 不识别方法“Int64 get_Item(Int32)”,因此该方法无法转换为存储表达式。

且看代码

List<long> list = new List<long> { , ,  };
var entity = entitySet.Where(en => en.SID == list[]).ToList();

在这里数组的下标运算放在了linq表达式中,这种情况也是不被允许的。但是用contains,形如list.Contains(en.SID)

或者把下标操作放在linq语句都是可以的。

关系数据库不能识别 含有下标运算的表达式树翻译成的sql查询,为什么会这样呢? 也许要去问微软的工程师吧!

情形4:Only parameterless constructors and initializers are supported in LINQ to Entities

请看如下代码:

 EntityRepository repository = new EntityRepository();
DbSet<Entity> entitySet = repository.Context.Set<Entity>();
List<Tuple<long, string>> tuple = entitySet.Select(en => new Tuple<long, string>(en.SID, en.Name)).ToList();

仍然是针对EF的查询。这里的Tuple是元组类,可用多个参数构造成一个元组类(或叫匿名类)。运行时报异常,中文意思为:

LINQ to Entities 仅支持无参数构造函数和初始值设定项。 看来是在linq中使用了带参数的构造函数,linq是不支持这一点的。我们使用匿名类来试试看。

var tuple = entitySet.Select(en => new { en.SID, en.Name }).ToList();

运行正常。但是有些情况下,我们非要使用Tuple来接受这两个参数以便于函数之间的传值,那该怎么办呢? 其实搞清楚真正的原因,自然就有办法了。因为我们在select后

.ToList()时要访问数据库,在这种情况下,带构造函数的Tuple自然是不能苟活的。所以只有在断开数据库后进行此操作才会万无一失。

List<Tuple<long, string>> tuple = entitySet.Select(en => new { en.SID, en.Name })
.AsEnumerable()
.Select(en => new Tuple<long, string>(en.SID, en.Name)).ToList();

entitySet.Select(en => new { en.SID, en.Name })返回的是IQueryable类型,加了个AsEnumerable()之后便是IEnumerable类型,以此来断开数据库连接。

当然,用ToList()或ToArray()亦可!

Linq to EF 与Linq to Object 使用心得的更多相关文章

  1. Java进击C#——应用开发之Linq和EF

    本章简言 上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知 ...

  2. linq和EF查询的用法和区分

    我们做项目时,难免会遇到用的不知道是啥,及把linq和EF搞混了 今天我带领大家梳理下思路: 首先说linq查询,然后介绍EF查询 1.linq查询 当我们使用linq查询时,转到定义会调到Query ...

  3. 应用开发之Linq和EF

    本章简言 上一章笔者对于WinForm开发过程用到的几个知识点做了讲解.笔者们可以以此为开端进行学习.而本章我们来讲一个跟ORM思想有关的知识点.在讲之前让我们想一下关于JAVA的hibernate知 ...

  4. [转载]EF或LINQ 查询时使用IN并且根据列表自定义排序方法

    原文地址:EF或LINQ 查询时使用IN并且根据列表自定义排序方法作者:李明川 EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很 ...

  5. EF或LINQ 查询时使用IN并且根据列表自定义排序方法

    EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很多人不熟,经常会碰到一些写SQL语句时经常会用到的一些方法,而使用EF或LINQ ...

  6. 【转发】Linq To EF添加记录后获取添加的自增ID和叫“ID”的列不是自增列不让插入的问题

    1:添加记录后,如何获取新添加的ID的值 比如,一个实体 TestEntity   对应一个表TestEntity(ID主键自增,Name,age),使用linq to ef   添加一条记录后,如何 ...

  7. Linq To EF (添加记录后获取添加的自增ID和叫“ID”的列不是自增列不让插入的问题)

    1:添加记录后,如何获取新添加的ID的值 比如,一个实体 TestEntity   对应一个表TestEntity(ID主键自增,Name,age),使用linq to ef   添加一条记录后,如何 ...

  8. Linq To SQL和Linq To Object的批量操作InsertAllOnSubmit介绍

    无论是Linq To SQL还是Linq To Object(Entity frameworks)它们都为开发人员提供了Insert操作,及Insert集合操作,即InsertOnSubmit和Ins ...

  9. Linq To EF 用泛型时生成的Sql会查询全表的问题

    1.问题的现象 public class LinqHepler<T> where T:class { private EFDBContext _context = null; /// &l ...

随机推荐

  1. apache commons-email1.3使用

    apache commons-email1.3下载地址:   https://repository.apache.org/content/repositories/orgapachecommons-0 ...

  2. asp.net2.0 国际化

    公司业务需要在国外开展了, 因此以前的系统要做多国语言了, 从网上搜集了好多资料, 最后选择了一个比较简单的方案 1.  打开vs2005, 新建网站, 首先在配置文件中添加配置: <syste ...

  3. Linux 本地yum源搭建和网络yum源搭建

    一.本地yum源搭建 首先挂载上光盘 [root@www /]# mount /dev/cdrom /media/cdrom/ 系统默认已经安装了可使用yum的软件包,所以可以直接配置: [root@ ...

  4. CSS居中的实现用法实例

    转载的一篇文章,讲解css内容居中的. 网上有关css 居中的文章不胜枚举,不过大多没有做系统的总结.这里分享的这篇有关css居中的文章,个人感觉不错,值得收藏. 一.水平居中1,将元素水平居中(us ...

  5. Android Material Design:滑动指示选项卡android.support.design.widget.TabLayout的简单使用

    该TabLayout的功用,简单的说,就是当用户在该TabLayout的选项卡子item中选择触摸时候,文字和下方的指示器横条滑动指示.这个功能就是以前APP开发常用的选项卡某一卡片被切换.选中时候的 ...

  6. CentOS如何分区

    安装Linux CentOS时,需要在硬盘建立CentOS使用的分区,在大多情况下,至少需要为CentOS建立以下3个分区. (1)/boot分区(不是必须的):/boot分区用于引导系统,它包含了操 ...

  7. 微软更换考试中心后报名攻略以及MCT半价

    微软从Prometric更换为Pearson的考试中心,比起以前的预约流程更加便捷. Pearson VUE为微软公司提供MCP考试服务 Pearson VUE为微软公司提供MCP考试服务 http: ...

  8. c 指针兼容性问题

    指针兼容性问题: const指针不能赋值给非const指针. 非const指针可以赋值给const 指针,但前提是只是一层间接运算 Example: int *pt1; const *pt2; con ...

  9. c++迭代器(iterator)详解

    1. 迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型.(1) 每种容器类型都定义了自己的迭代器类型,如vector:vector<int>::iterator iter ...

  10. Window.ActiveXObject的用法 以及如何判断浏览器的类型

    (window.ActiveXObject) 什么意思? 解:判断浏览器是否支持ActiveX控件,如果浏览器支持ActiveX控件可以利用 var xml=new ActiveXObject(&qu ...