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

时间:2009-12-08 21:48:03

标签: .net linq linq-to-sql orm

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

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

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

先决条件:

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

1 个答案:

答案 0 :(得分: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);
        }
    

    示例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]
    
  2. 身份管理员短路,没有往返 - 即

    var obj = ctx.Single(x=>x.Id == id);
    var obj = ctx.Where(x=>x.Id == id).Single();
    
    如果具有该身份的对象已经实现并存储在身份管理器中,

    也适用于FirstSingleOrDefaultFirstOrDefault。请参阅LINQ-to-SQL(也是herehere;您可以通过附加到.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();
    }
    

    日志输出仅显示两次行程;一个是第一次获得对象,一个是计数;它还显示了由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
    
  3. UDF支持;一个简单的例子也适用于LINQ到对象:

    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()
    
  4. 如果我感觉真的邪恶,recursive lambda;可能不值得以任何方式支持此...同样,4.0表达式(DLR)节点类型。