65.9K
CodeProject 正在变化。 阅读更多。
Home

学习 SQL 到 LINQ(可视化表示)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (102投票s)

2010 年 12 月 13 日

CPOL

6分钟阅读

viewsIcon

273407

讨论了将 SQL 查询转换为 LINQ 查询的可视化表示。

引言

许多开发人员在转向新的 LINQ to SQL 时,发现用 C# 编写 SQL 查询以使用 LINQ 查询数据非常困难。LINQ 是一种集成到 C# 中的查询语言,用于从 ObjectCollect、SQL、XML 等查询数据。在开始阅读本文之前,建议先了解 LINQ 支持的功能。

在本文中,我将讨论基本的 SQL 查询以及与 SQL 查询类似的 LINQ 查询,并附带 LINQ 查询的可视化表示。在开始讨论之前,这是我用于本文的表结构。

用户

01_userclient_table.png

UserClients

02_user_table.png

LINQ 结构

03_linq_structure.png

注意:在本文中,所有 LINQ 查询均在 LINQPAD 应用程序中执行。

LINQ 查询列表

情况 1:Select

从 user 表中获取所有用户的所有列的 SQL 查询将是:

SELECT * FROM [User]

执行上述操作的 LINQ 查询是:

var user = from u in Users
select u;

这是您编写的从 user 表获取数据的 LINQ 查询的图形表示 breakdown。

04_select_user.png

情况 2:Select(带列)

这种情况与上面类似,但不同之处在于我们不选择所有列;相反,我只选择两列:FirstNameLastName。选择仅两列的所有行的 SQL 查询是:

Select FirstName, LastName from [User]

现在是 LINQ 查询:

from u in Users
select new
{
    u.FirstName,
    u.LastName
};

因此,您需要创建一个新的匿名类型来仅从 user 对象中获取 FirstNameLastName。此查询的图形表示如下:

05_select_user.png

情况 3:过滤选定的数据

对于整数数据

要对选定的数据应用过滤器,我们使用带有列值的 WHERE 子句,因此 SQL 查询将是:

Select firstname,LastName from [User] where id = 3

在 LINQ 中,我们也需要使用 WHERE 子句,因此查询将是:

from u in Users
where u.Id ==3
select new
{
   u.FirstName,
   u.LastName
}

此图形表示显示了与过滤数据相关的 LINQ 查询的 breakdown。

06_select_filter.png

对于字符串数据

为了过滤字符串,我们使用 LIKE

SELECT  [Id], [FirstName], [LastName], [Email], 
        [DisplayName], [Address1], [Address2], [Password], [Role]
FROM [User]
WHERE [Email] LIKE '%pranay%'

SELECT  [Id], [FirstName], [LastName], [Email], 
        [DisplayName], [Address1], [Address2], [Password], [Role]
FROM [User]
WHERE [Email] LIKE 'pranay%'

要对字符串数据类型应用过滤器,您需要使用 C# 中可用的 ContainsStartWith 函数,这样它就会生成与上述 SQL 查询相同的结果。

from u in Users
where u.Email.Contains ("pranay")
select u

from u in Users
where u.Email.StartsWith ("pranay")
select u

使用字符串字段过滤的 LINQ 查询的图形表示。

07_select_filter_like.png

情况 4:连接两个表

内连接(Inner Join)

内部连接是我们如何获取两个表之间的公共记录,即表中的相关记录。以下是内部连接的 SQL 查询:

SELECT [User].[Id], [FirstName], [LastName], [UserId], [MobileNo]
FROM [User]
INNER JOIN
[UserClients]
ON [User].[id] = [UserId]

LINQ 使用 Join 关键字和 Equals 来连接两个集合,从而执行相同的操作。

var user = from u in Users
join uc in UserClients on u.Id equals uc.UserId
select new {
  u.Id,
  u.FirstName,
  u.LastName,
  uc.MobileNo,
  uc.imeiNO,
  uc.Id,
};

下面显示了 LINQ 查询的内部连接的图形表示。如您所见,User connection 基于 On.. Equals 中的条件添加到 UserClients。

外部连接

外部连接是我们如何获取两个表之间的公共记录,即表中的相关记录;来自左表的所有记录,如果在右表中未找到,则会获得 null 值。外部连接的 SQL 查询将如下所示:

SELECT [t0].[Id], [FirstName], [LastName], 
       [UserId] AS [UserId], [MobileNo] AS [MobileNo]
FROM [User] AS [t0]
LEFT OUTER JOIN [UserClients]  ON ([t0].[id]) = [UserId]

在 LINQ 中,要实现外部连接,您需要使用 DefaultIfEmpty() 函数,如下所示:

var user = from u in Users
join uc in UserClients on u.Id equals uc.UserId
into myuserwithclient
from m in myuserwithclient.DefaultIfEmpty()
select new {
 u.Id,
 u.FirstName,
 u.LastName,
 m.UserId,
 m.MobileNo
};

外部连接 LINQ 查询的图形表示与内部连接相同,但 DefaultIfEmpty() 函数还有一步。

情况 5:排序数据

在 SQL 中,要对获取的数据进行排序,我们需要应用 ORDER BY 子句以及 ASCDESC 关键字,因此 SQL 查询将是:

--Ascending
Select * from [User] order by firstName

--Descending
Select * from [User] order by firstName desc

LINQ 使用 ORDER BY 结合 ASCENDINGDESCENDING 关键字,因此最终的 LINQ 查询将是:

//Ascending
var user = from u in Users
orderby u.FirstName
 select new
{
   u.FirstName,
   u.LastName 
}

//Descending
var user = from u in Users
orderby u.FirstName descending
select new
{
   u.FirstName,
   u.LastName 
};

这是 LINQ 查询的图形 breakdown。

情况 6:分组数据

选定数据的分组允许执行聚合函数,如 SUMMAXMINCOUNT 等。要在 SQL 中对数据进行分组,您需要使用 GROUP BY 子句,但需要记住的是,您需要在 group by 子句中包含 select 列表列,否则您将收到语法错误。

SELECT COUNT(*) AS [test], [UserId]
FROM [UserClients]
GROUP BY [UserId]

LINQ 使用 Group ... By 来分组数据,因此查询如下所示:

var user =  from u in UserClients
group u by u.UserId into c
select new
{
 t1 = c.Key,
 tcount = c.Count()
};

注意:在 LINQ 中对对象集合应用 group by 后,您的 group by 列将转换为键列,您可以在上面的 LINQ 查询 UserId 中看到。Group...By LINQ 查询的图形 breakdown 是:

情况 7:使用 IN 和 NOT IN 子句过滤数据

大多数开始使用 LINQ 查询的开发人员在不得不使用 LINQ 编写 INNOT IN 查询时会感到困惑。以下是 SQL 查询:

//IN
SELECT [Id], [UserId], [IMEINo]
FROM [UserClients]
WHERE [UserId] IN (3, 4)

//NOT IN
SELECT [Id], [UserId],  [IMEINo]
FROM [UserClients]
WHERE [UserId] IN (3, 4)

如上所示,查询使用 INNOT IN 子句从记录列表中进行过滤。执行此任务的 LINQ 查询利用了 C# 的 Contains 函数,该函数从记录列表中过滤记录。

//IN
int[] chosenOnes = { 3, 4 };
var user = from u in UserClients
where chosenOnes.Contains(u.UserId.Value)
select new  { u.id,u.userid, u.ImeiNo};

//NOT IN
int[] chosenOnes = { 3, 4 };
var user = from u in UserClients
where !chosenOnes.Contains(u.UserId.Value)
select u;

注意INNOT IN 在 LINQ 查询中使用相同的函数,但它只使用一个!(not) 符号。以下是图形表示:

情况 8:按行号过滤数据

我现在将展示如何按分配给记录的行号过滤数据。要在 SQL Server (SQL Server 2005) 中过滤数据,我们使用 RowNumber 函数,然后我们使用 <=>=BETWEEN。以下是 SQL 查询:

SELECT *
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [id]) AS [ROW_NUMBER],
           [id], [FirstName], [LastName], [Email], [DisplayName], 
           [Address1], [Address2], [Password], [Role]
    FROM [User] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN 11 AND 20
ORDER BY [t1].[ROW_NUMBER]

在上面的查询中,如您所见,ROW_NUMBER() 函数为记录分配一个编号,然后我们可以在外部查询中使用该编号来过滤 11 到 20 之间的数据。LINQ 使用两个函数:

  • Skip:跳过序列中的指定数量的元素,然后返回剩余的元素(请参阅此链接)。
  • Take:从序列的开头返回指定数量的连续元素(请参阅此链接)。

LINQ 查询如下所示:

var users = from u in Users
select u;

var filterUsers= users.OrderBy (p => p.Id).Skip (10).Take(10);

在上面的代码中,我们首先选择数据,然后应用 SkipTake 来获取 11 到 20 条记录之间的数据。以下是图形表示;

最好的例子是当您在使用自定义分页的 grid 控件或 list 控件时。更详细的示例可以在这里看到:LINQ tO SQL GridView (Enhanced GridView)

情况 9:SQL ISNULL 函数

注意:在此情况下,没有图形表示,我将只展示 LINQ 可以实现的另一个函数。

在继续之前,请阅读以下帖子:

解决方案 1

我们可以使用三元运算符,如以下示例所示,对于 null 值,使用 MobileNo = "N/A"

var user = from u in Users
join uc in UserClients on u.Id equals uc.UserId
into myuserwithclient
from m in myuserwithclient.DefaultIfEmpty()
select new {
u.Id,
FirstName = u.FirstName,
LastName = u.LastName,
UserId = m.UserId,
MobileNo = (m.MobileNo == null) ? "N/A" : m.MobileNo
};

解决方案 2

使用特殊合并运算符(??),如以下示例所示,对于 null 值,使用 MobileNo = "N/A"

var user = from u in Users
join uc in UserClients on u.Id equals uc.UserId
into myuserwithclient
from m in myuserwithclient.DefaultIfEmpty()
select new {
u.Id,
FirstName = u.FirstName,
LastName = u.LastName,
UserId = m.UserId,
MobileNo = m.MobileNo == null ?? "N/A" 
};

摘要

本文展示了许多 LINQ 查询的可视化表示。希望您喜欢使用 LINQ!

© . All rights reserved.