最近在写代码的过程中用到了Linq查询,在查找资料的过程中发现网上的资料千奇百怪,于是自己整理了一些关于Linq中容易让人困惑的地方。

本文全部代码基于:UserInfo与Class两个表,其中Class中的UserId与UserInfo中的Id对应

本文唯一访问地址:http://www.cnblogs.com/yubaolee/p/BestLinqQuery.html

linq联合查询

内联查询

内联是一个实际使用频率很高的查询,它查询两个表共有的且都不为空的部分

 from user in UserInfo
join c in Classes on user.Id equals c.UserId
select new
{
user.UserName,
user.Id,
c.ClassName
}

查询结果

对应的SQL语句

SELECT [t0].[UserName], [t0].[Id], [t1].[ClassName]
FROM [UserInfo] AS [t0]
INNER JOIN [Class] AS [t1] ON [t0].[Id] = [t1].[UserId]

左联查询

左联应该是联合查询中使用频率最高的查询。它以左表为准,进行联合查询。如果右表中不存在对应的结果,则置空。(注意:在Linq中是不存在右联连的说法,因为右联无非是把左边的表移动到右边,查询的结果与左联是一样的)

from user in UserInfo
join c in Classes on user.Id equals c.UserId into temp
from c in temp.DefaultIfEmpty()
select new
{
user.UserName,
user.Id,
c.ClassName
}

查询结果

对应SQL语句

SELECT [t0].[UserName], [t0].[Id], [t1].[ClassName] AS [ClassName]
FROM [UserInfo] AS [t0]
LEFT OUTER JOIN [Class] AS [t1] ON [t0].[Id] = [t1].[UserId]

!注意一下左联那个【temp】,它其实是一个IEnumerable集合。所以我们可以得到到左联的另一种结果:

from user in UserInfo
join c in Classes on user.Id equals c.UserId into temp
select new
{
user,
temp
}

查询结果(为了更明确表达集合,在Class表里特别加了一条记录,所以class那边共有3条)

对应SQL语句,与左联的SQL基本一样,但多了一个统计行数的列

SELECT t0.*, [t1].[Id] AS [Id2], t1.*, (
SELECT COUNT(*)
FROM [Class] AS [t2]
WHERE [t0].[Id] = [t2].[UserId]
) AS [value]
FROM [UserInfo] AS [t0]
LEFT OUTER JOIN [Class] AS [t1] ON [t0].[Id] = [t1].[UserId]

全联接

全联连是得到两个表的交叉结果(在SQL中称为cross join),这种联连方式得到的结果在没有过滤条件的情况下,基本没什么用。看看即可,代码如下:

 from user in UserInfo
from c in Classes
select new
{
user.UserName,
user.Id,
c.ClassName
}

查询结果

对应SQL语句

SELECT [t0].[UserName], [t0].[Id], [t1].[ClassName]
FROM [UserInfo] AS [t0], [Class] AS [t1]

合并(Union)

这种查询其实也很少用,但在某些变态业务需求下会非常有用,注意查询的结果。它是合并两个表相同列数的结果,并且如果结果中有相同的行,那么只取一行记录。

(
from userinfo in UserInfo
select new {
Id = (System.Int32?)userinfo.Id,
Name = userinfo.UserName
}
).Union
(
from c in Classes
select new {
Id = (System.Int32?)c.UserId,
Name = c.ClassName
}
)

查询结果

对应SQL语句

SELECT [t0].[Id] AS [value], [t0].[UserName]
FROM [UserInfo] AS [t0]
UNION
SELECT [t1].[UserId] AS [value], [t1].[ClassName]
FROM [Class] AS [t1]

Linq 分组查询

分组查询(group by)也是我们在实际项目中一个常用的操作,查询操作如下:

from c in Classes
group c by c.UserId into temp
select temp

查询结果

注意一下查询结果,外层是一个我们常用的IQueryable<T>,里面是一个类似Dictionary的K-V集合。简单点说Group返回的是一个集合的集合,因此输出时需用双重循环。

我们在使用它的结果时,应该这样调用:

 var result = from c in _context.Classes
group c by c.UserId
into temp
select temp; foreach (var c in result)
{
Console.WriteLine(c.Key);
foreach (var citem in c)
{
Console.WriteLine(citem.ClassName);
}
}

实体增加字段处理

我在本文例子中的UserInfo实体类如下:

 public partial class UserInfo
{
public int Id { get; set; }
public string UserName { get; set; }
public string UserType { get; set; }
public int Money { get; set; }
}

现在我想在该实体中类中添加一个属性。为了保持原实体类的纯洁。我添加一个新的partial类:

public partial class UserInfo
{
/// <summary>
/// 测试扩展属性
/// </summary>
public string UserExt
{
get { return UserName + ":" + UserType; }
}
}

然后我们用EF访问一下,发现是可以访问的:

但如果我们这样使用时:

from user in _context.UserInfoes
select new
{
user.Id,
user.UserExt
};

会发现编译是没有问题的。但运行时会出现下面异常:

具体错误信息如下: The specified type member 'UserExt' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

即"UserExt"类型并不能被linq支持。因为在进入到foreach进行真正取数据之前。EF已经把linq转成SQL语句,而UserExt会被转成对应的数据库字段。因为数据库中并没有该字段,所以会出现这个问题。解决的方法很简单:

from user in _context.UserInfoes.ToList()
select new
{
user.Id,
user.UserExt
};

即先执行ToList(),提前让linq进行执行,生成UserInfo集合,这样就可以正常访问UserExt了。别看这个小小的改动。在多表联查过滤字段的情况下,你会体会到无尽的妙处!

你可能会想到一个问题,如果我再加一个完整的属性会出现什么情况?

 public partial class UserInfo
{
public string UserExt
{
get { return UserName + ":" + UserType; }
}
//新增一个完整的属性
public string UserExt2 { get; set; }
}

上面的UserExt2是我们新加入的一个属性,现在我们来执行一下查询。我想真正去研究过Linq的人肯定知道结果了。

在Linq操作中实体中的属性必须在配置映射时指定。我们的数据库中当然没有UserExt2这个字段,所以增加Ignore标识,或调用一下:

this.Ignore(t => t.UserExt2);

.NET深入实战系列—Linq to Sql进阶的更多相关文章

  1. Linq实战 之 Linq to Sql及Entity Framework操作详解

    Linq实战 之 Linq to Sql及Entity Framework操作详解 一:linq to db的框架 1. linq to sql 2. linq to ado.net entity f ...

  2. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

  3. SCCM 2012 R2实战系列之一:SQL安装

    大家好,从今天开始跟大家一起分享自己学习SCCM 2012 R2的一些心得和具体的部署配置,希望能帮到大家.由于SCCM部署的步骤比较复杂,内容也比较多,所以我把SCCM整个部署过程分为以下三个章节: ...

  4. MySQL架构优化实战系列4:SQL优化步骤与常用管理命令

  5. .NET面试题系列[14] - LINQ to SQL与IQueryable

    .NET面试题系列目录 名言警句 "理解IQueryable的最简单方式就是,把它看作一个查询,在执行的时候,将会生成结果序列." - Jon Skeet LINQ to Obje ...

  6. LINQ to SQL 系列 如何使用LINQ to SQL插入、修改、删除数据

    http://www.cnblogs.com/yukaizhao/archive/2010/05/13/linq_to_sql_1.html LINQ和 LINQ to SQL 都已经不是一个新事物了 ...

  7. SQL Server 性能优化实战系列(二)

    SQL Server datetime数据类型设计.优化误区 一.场景 在SQL Server 2005中,有一个表TestDatetime,其中Dates这个字段的数据类型是datetime,如果你 ...

  8. LINQ to SQL 系列 如何使用LINQ to SQL插入、修改、删除数据 (转)

    http://www.cnblogs.com/yukaizhao/archive/2010/05/13/linq_to_sql_1.html LINQ和 LINQ to SQL 都已经不是一个新事物了 ...

  9. LINQ系列:LINQ to SQL Where条件

    1. 单一条件查询 var expr = context.Products .Where(p => p.ProductName == "LINQ to SQL"); SELE ...

随机推荐

  1. iOS逆向工程之KeyChain与Snoop-it

    今天博客的主题是Keychain, 在本篇博客中会通过一个登陆的Demo将用户名密码存入到KeyChain中,并且查看一下KeyChain中存的是什么东西,把这些内容给导出来.当然本篇博客的重点不是如 ...

  2. 如何利用tcpdump对mysql进行抓包操作

    命令如下: tcpdump -s -l -w - dst -i eno16777736 |strings 其中-i指定监听的网络接口,在RHEL 7下,网络接口名不再是之前的eth0,而是 eno16 ...

  3. 9、委托、事件、Lambda

    开始 关于委托,肯定是要有问题的. 第一个问题,委托用来干什么? 看.net中的表述:在.net平台下,委托类型用来定义和相应应用程序中的回调.(回调?处理内存中两个实体双向通信的一种技术.)   第 ...

  4. Ubuntu搭建lnmp环境

    1.安装nginx 安装 sudo apt-get install nginx 服务启动.停止.重启 /etc/init.d/nginx start /usr/sbin/nginx -c /etc/n ...

  5. 浅谈Slick(2)- Slick101:第一个动手尝试的项目

    看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...

  6. 【每日一linux命令1】linux命令路径

    一.路径: 执行命令前必须要考虑的一步是命令的路径,若是路径错误或是没有正确的指定,可能导致错误 的执行或是找不到该命令.要知道设置的路径,可执行以下命令: echo $PATH 显示结果: 这时我们 ...

  7. 进程监控工具supervisor 启动Mongodb

    进程监控工具supervisor 启动Mongodb 一什么是supervisor Superviosr是一个UNIX-like系统上的进程监控工具. Supervisor是一个Python开发的cl ...

  8. React 其实比 MVVM 架构更加卡顿

    React 号称通过引入 Virtual DOM 带来了性能的提升,而其实 React 之所以需要 Virtual DOM,是因为它的架构下,state 的变更是全量的,然后触发 render 返回全 ...

  9. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

  10. Math.random()

    Math.random() 日期时间函数(需要用变量调用):var b = new Date(); //获取当前时间b.getTime() //获取时间戳b.getFullYear() //获取年份b ...