Linq to EF 与Linq to Object 使用心得

 你们都知道Linq既能够用来查询数据库对象(我这里指的是Entity FrameWork里的Model对象),也能够用来查询内存中的IEnumerable对象。jquery

二者单独查询时都不会出现什么问题,不过混合在一块儿时(通常是用关键字来join链接),要注意的地方就多着了。sql

 

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

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

[csharp] view plain copy print ?
  1. List<MyObject> objectList = new List<MyObject>();  
  2. objectList.Add(new MyObject { Identity = 1, Name = "Jack", Age = 30 });  
  3. objectList.Add(new MyObject { Identity = 2, Name = "Sam", Age = 28 });  
  4. objectList.Add(new MyObject { Identity = 3, Name = "Lucy", Age = 23 });  
  5.   
  6. EntityRepository repository = new EntityRepository();  
  7. DbSet<Entity> entitySet = repository.Context.Set<Entity>();  
  8.   
  9. var objectNames = (from ob in objectList  
  10.                    join en in entitySet  
  11.                    on ob.Identity equals en.SID  
  12.                    select ob.Name).ToList();  
 

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

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

  1. SELECT   
  2. [Extent1].[SID] AS [SID],   
  3. [Extent1].[Name] AS [Name],   
  4. [Extent1].[Notes] AS [Notes]  
  5. FROM [dbo].[Entity] AS [Extent1]  
 

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

若是把以上代码改为select en.Name,仍然是整表查询。函数

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

 

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

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

[csharp] view plain copy print ?
  1. var entityNames = (from en in entitySet  
  2.                    join ob in objectList  
  3.                    on en.SID equals ob.Identity  
  4.                    select en.Name).ToList();  
 

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

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

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

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

MyObject要为int32, string或者Guid,才能运行经过,而且不是整表查询,而是针对name列的单独查询。你们能够一试。

 

因此在这里给出你们一点建议:

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

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

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

[csharp] view plain copy print ?
  1. IEnumerable<long> idList = objectList.Select(o => o.Identity);  
  2.   
  3. var entityNames = (from en in entitySet  
  4.                    join id in idList  
  5.                    on en.SID equals id  
  6.                    select en.Name).ToList();  
 

数据库查询语句以下:

  1. SELECT   
  2. [Extent1].[Name] AS [Name]  
  3. FROM  [dbo].[Entity] AS [Extent1]  
  4. INNER JOIN  (SELECT   
  5.     [UnionAll1].[C1] AS [C1]  
  6.     FROM  (SELECT   
  7.         cast(1 as bigint) AS [C1]  
  8.         FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]  
  9.     UNION ALL  
  10.         SELECT   
  11.         cast(2 as bigint) AS [C1]  
  12.         FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]  
  13. UNION ALL  
  14.     SELECT   
  15.     cast(3 as bigint) AS [C1]  
  16.     FROM  ( SELECT 1 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)”,所以该方法没法转换为存储表达式。

且看代码

[csharp] view plain copy print ?
  1. List<long> list = new List<long> { 1, 2, 3 };  
  2. var entity = entitySet.Where(en => en.SID == list[1]).ToList();  
 

 

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

或者把下标操做放在linq语句都是能够的。

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

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

请看以下代码:

[csharp] view plain copy print ?
  1. EntityRepository repository = new EntityRepository();  
  2. DbSet<Entity> entitySet = repository.Context.Set<Entity>();  
  3. List<Tuple<long, string>> tuple = entitySet.Select(en => new Tuple<long, string>(en.SID, en.Name)).ToList();  
 

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

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

[csharp] view plain copy print ?
  1. var tuple = entitySet.Select(en => new { en.SID, en.Name }).ToList();  
 

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

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

[csharp] view plain copy print ?
  1. List<Tuple<long, string>> tuple = entitySet.Select(en => new { en.SID, en.Name })  
  2.                                             .AsEnumerable()  
  3.                                             .Select(en => new Tuple<long, string>(en.SID, en.Name)).ToList();  
 

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

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

http://jquery.cuishifeng.cn/

相关文章
相关标签/搜索