真正复杂的LINQ(to SQL)查询示例

Ale*_*nin 5 .net linq orm linq-to-sql

我们正在考虑为ORMBattle.NET添加更多的LINQ测试,但没有更多的想法.所有LINQ测试都检查常见的LINQ功能:

  • 任何测试都必须将LINQ传递给IEnumerable
  • 对于任何测试,必须至少有一个ORM,它通过(实际上,无论是否列出@ ORMBattle都无关紧要).

目前,LINQ测试序列的目标是自动计算LINQ实现覆盖率.

先决条件:

如果您对可添加的内容有任何想法,请分享.我肯定会接受满足上述要求的任何 LINQ查询示例,并且可能 - 可以实现与测试套件改进相关的一些好主意(例如,如果您建议我们手动研究翻译质量,这个不行,因为我们不能自动化这个).

Mar*_*ell 8

  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);
        }
    
    Run Code Online (Sandbox Code Playgroud)

    示例LINQ-to-SQL输出(EF在sparks中爆炸):

    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]
    
    Run Code Online (Sandbox Code Playgroud)
  2. 身份管理员短路没有往返 - 即

    var obj = ctx.Single(x=>x.Id == id);
    var obj = ctx.Where(x=>x.Id == id).Single();
    
    Run Code Online (Sandbox Code Playgroud)

    等应该不会需要去到数据库中,如果与身份的对象已经被物化并存储在身份管理器; 也适用于First,SingleOrDefault,FirstOrDefault.请参阅LINQ-to-SQL(此处此处 ;您可以通过附加来验证.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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    日志输出仅显示两次行程; 一个是第一次获得对象,一个是计数; 它还显示了Materializer返回的相同对象引用:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  3. UDF支持; 一个简单的例子也适用于LINQ到对象:

    partial class MyDataContext {
         [Function(Name="NEWID", IsComposable=true)] 
         public Guid Random()  { return Guid.NewGuid();}
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后按顺序排列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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    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()
    
    Run Code Online (Sandbox Code Playgroud)
  4. 如果我感觉真的很邪恶,那就是递归的lambda ; 可能不值得以任何方式支持这个...同样,4.0表达式(DLR)节点类型.