真正复杂的 LINQ (to SQL) 查询示例
Posted
技术标签:
【中文标题】真正复杂的 LINQ (to SQL) 查询示例【英文标题】:Really complex LINQ (to SQL) query example 【发布时间】:2009-12-08 21:48:03 【问题描述】:我们正在考虑为 ORMBattle.NET 添加更多 LINQ 测试,但没有更多想法。那里的所有 LINQ 测试都在检查常见的 LINQ 功能:
任何测试都必须通过 LINQ to IEnumerable 对于任何测试,都必须至少有一个 ORM,它通过(实际上是否在 @ORMBattle 上列出并不重要)。目前 LINQ 测试序列的目标是自动计算 LINQ 实现覆盖率分数。
先决条件:
Code of tests for LINQ to SQL is here。这必须让您对已经涵盖的内容有所想象。 其他工具的测试(实际上它们是由this T4 template 生成的)是here。如果您对可以添加的内容有任何想法,请分享。我肯定会接受 任何 满足上述要求的 LINQ 查询示例,并且可能 - 一些与改进测试套件相关的好主意,可以实现(例如,如果您会建议我们手动研究翻译质量,这是行不通的,因为我们无法自动执行此操作)。
【问题讨论】:
“可以拒绝支持外来类型和方法的测试。“外来”意味着它将被大多数 ORM 供应商@ORMBattle.NET Development Google Group 认为是外来的。”然后询问有权批准测试的多数来创建测试。他们基本上可以通过将其识别为“异国情调”来拒绝任何他们喜欢的东西。 问题是“为我的项目贡献一些东西吗?”这似乎不是合适的论坛。 好的,澄清一下:如果你想使用例如Uri 类型在您的测试中,很有可能会被识别为外来类型 - 仅仅是因为在关系范围内没有类似的类型,但另一方面,很可能可以使用字符串操作来模拟它的某些方法。跨度> 另一方面,我几乎不相信像 Uri 这样的类型会在未来几年内至少有一个 ORM 或 LINQ 提供商支持。好的,我将删除条件 3 - 1 和 2 来定义范围。 > 问题是“为我的项目贡献一些东西吗?”是的,部分 - 即您必须知道非常奇特的背景才能回答它。但是这个问题与编码有关,需要专业知识,并且很可能只需几个 LOC 就可以回答。所以我不太确定,决定试试这个。 【参考方案1】:Expression.Invoke
用于子表达式;适用于 LINQ-to-SQL 和 LINQ-to-Objects,但不适用于 3.5SP1 中的 EF(对于 IEnumerable<T>
,请先调用 .AsQueryable()
):
Expression<Func<Customer, bool>> pred1 = cust=>cust.Country=="UK";
Expression<Func<Customer, bool>> pred2 = cust=>cust.Country=="France";
var param = Expression.Parameter(typeof(Customer), "x");
var final = Expression.Lambda<Func<Customer, bool>>(
Expression.OrElse(
Expression.Invoke(pred1, param),
Expression.Invoke(pred2, param)
), param);
using (var ctx = new DataClasses1DataContext())
ctx.Log = Console.Out;
int ukPlusFrance = ctx.Customers.Count(final);
示例 LINQ-to-SQL 输出(EF 在火花中爆炸):
SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
WHERE ([t0].[Country] = @p0) OR ([t0].[Country] = @p1)
-- @p0: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
-- @p1: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [France]
没有往返的身份管理器短路 - 即
var obj = ctx.Single(x=>x.Id == id);
var obj = ctx.Where(x=>x.Id == id).Single();
如果具有该身份的对象已经物化并存储在身份管理器中,等应该不需要进入数据库;也适用于First
、SingleOrDefault
、FirstOrDefault
。请参阅 LINQ-to-SQL(也可以是 here 和 here;您可以通过附加到 .Log
进行验证);示例:
using (var ctx = new DataClasses1DataContext())
ctx.Log = Console.Out;
var first = ctx.Customers.First();
string id = first.CustomerID;
Console.WriteLine("Any more trips?");
var firstDup = ctx.Customers.First(x=>x.CustomerID==id);
Console.WriteLine(ReferenceEquals(first, firstDup)); // true
Console.WriteLine("Prove still attached");
int count = ctx.Customers.Count();
日志输出仅显示两次行程;一个用于第一次获取对象,一个用于计数;它还显示了物化器返回了相同的对象引用:
SELECT TOP (1) [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[
ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t
0].[Country], [t0].[Phone], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.492
6
Any more trips?
True <==== this is object reference equality, not "are there any more trips"
Prove still attached
SELECT COUNT(*) AS [value]
FROM [dbo].[Customers] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.492
6
UDF 支持;举一个同样适用于 LINQ-to-Objects 的简单示例:
partial class MyDataContext
[Function(Name="NEWID", IsComposable=true)]
public Guid Random() return Guid.NewGuid();
然后通过x => ctx.Random()
订购;示例:
using (var ctx = new DataClasses1DataContext())
ctx.Log = Console.Out;
var anyAtRandom = (from cust in ctx.Customers
orderby ctx.Random()
select cust).First();
带输出:
SELECT TOP (1) [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
ORDER BY NEWID()
如果我感觉真的邪恶,recursive lambda;可能不值得以任何方式支持它...同样,4.0 表达式 (DLR) 节点类型。
【讨论】:
非常感谢!我们肯定会在测试中添加 1 和 3。 2 似乎很主观(例如,我们决定不花任何时间在这上面)+ 暗示 SQL 查询检测(目前测试不关注 SQL),所以我会问其他人。 4 可能不受任何人支持,因为这必须暗示〜UDF 生成。所以让我们把它留到一些离开证明之前;)我同意,4 很有趣,主要是作为一个棘手的案例。但也许我们会添加一个测试以成功检测递归 lambda。 P.S. Marc,你是一位真正的专家 :) 我几乎没想到会在这里得到新的东西(我主要考虑的是特定的 VB.NET 方法),但案例 1 对我来说绝对是新的。我会问我们团队的人——他们可能知道这件事。虽然这看起来不太可能。以上是关于真正复杂的 LINQ (to SQL) 查询示例的主要内容,如果未能解决你的问题,请参考以下文章
LINQ TO SQL 和 ADO.NET ENTITY 有啥区别呢?
使用 linq to sql 后端通过 WCF 查询 DTO 对象