【问题标题】:LINQ to SQL: Advanced queries against lists, arrays and lists of objectsLINQ to SQL:针对列表、数组和对象列表的高级查询
【发布时间】:2009-04-08 19:56:58
【问题描述】:

单个和多个列表

考虑以下列表:

List<Int32> appleIdentities = new List<int>(new[] { 1, 2, 3 });
List<Int32> chocolateIdentities = new List<int>(new[] { 2, 3, 4 });
List<Int32> icecreamIdentities = new List<int>(new[] { 11, 14, 15, 16 });

使用 LINQ to SQL;有没有可能写出这样一个语句:

SELECT
    DesertsID,
    DesertsName
FROM
    Deserts
WHERE
    Deserts.AppleIdentity IN (1, 2, 3) AND
    Deserts.ChocolateIdentity IN (2, 3, 4) AND
    Deserts.IcecreamIdentity IN (11, 14, 15m 16)

如果是的话;如果我想仅针对appleIdentities 列表查询我的沙漠数据库,代码会如何?



数组

考虑以下数组:

Int32[] appleIdentities = new[] {1, 2, 3, 4};
String[] chocolateNames = new[] {"Light", "Dark"};

使用 LINQ to SQL;有没有可能写出这样一个语句:

SELECT
    DesertsID,
    DesertsName
FROM
    Deserts
WHERE
    Deserts.AppleIdentity IN (1, 2, 3) AND
    Deserts.ChocolateName IN ('Light', 'Dark')

如果是的话;如果我想仅针对 appleIdentities 数组查询我的沙漠数据库,代码会如何?



对象列表

考虑以下几点:

public class Identities
{
    public Int32 appleIdentity { get; set; }
    public String chokolateName { get; set; }
}

List<Identities> identities = new List<Identities>(new[] {
    new Identities { appleIdentity = 1, chokolateName = "Light" },
    new Identities { appleIdentity = 2, chokolateName = "Dark" },
});

使用 LINQ to SQL;有没有可能写出这样一个语句:

SELECT
    DesertsID,
    DesertsName
FROM
    Deserts
WHERE
    Deserts.AppleIdentity IN (1, 2) AND
    Deserts.ChocolateName IN ('Light', 'Dark')

如果是的话;如果我想仅针对 Identities 对象列表中的 appleIdentity-property 查询我的沙漠数据库,代码会如何?


这是LINQ to SQL query against a list of entities的分支

【问题讨论】:

    标签: c# linq linq-to-sql


    【解决方案1】:

    如果我愿意,代码会是什么样子 查询我的沙漠数据库 只是 appleIdentities 列表?

    您可以像这样在多个语句中编写 linq 查询,并在运行时选择要在 where 子句中使用的过滤器。

    var query = db.Desserts;
    if (filterbyAppleIdentity)
        query = query.Where( q => appleIdentities.Contains(q.DesertsID));
    if (filterbyChocolateIdentities)
        query = query.Where( q => chocolateIdentities.Contains(q.DesertsID));
    if (filterbicecreamIdentities)
        query = query.Where( q => icecreamIdentities.Contains(q.DesertsID));
    
    var deserts = query.ToList();
    

    你也可以编写一个扩展方法来做到这一点,而不用 if 语句:(编辑固定的错字,返回类型应该是 IQueriable

    public static class LinqExtensions {
      public IQueriable<T> CondWhere<T>(this IQueriable<T> query, bool condition, Expression<Func<T,bool>> predicate) {
         if (condition)
            return query.Where(predicate);
         else 
            return query;
      }
     }
    

    并像这样编写您的 linq 查询:

      var deserts = db.Desserts;
          .CondWhere(filterbyAppleIdentity, q => appleIdentities.Contains(q.DesertsID));
          .CondWhere(filterbyChocolateIdentities, q => chocolateIdentities.Contains(q.DesertsID));
          .CondWhere(filterbicecreamIdentities, q => icecreamIdentities.Contains(q.DesertsID)).ToList();
    

    另一种方法是合并 id 列表:

    var deserts = db.Deserts
            .Where( d => appleIdentities.Union(chocolateIdentities).Union(icecreamIdentities).Contains(d.DesertsID);
    

    对于对象列表,您可以使用 .Select 扩展方法将列表投影到 int 或字符串 IEnumerable 中,并且您可以以相同的方式在查询中使用 contains:

    var deserts = db.Deserts
        .Where(d => 
            identities.Select(i => i.appleIdentity).Contains(d => d.DesertID) &&
            identities.Select(i => i.chokolateName).Contains(d => d.DesertsName)
         )
    

    【讨论】:

    • 为什么投反对票?你能解释一下我的回答有什么问题吗?
    • 听听!永远不要在不提供反馈的情况下投反对票。不完全有建设性:/
    • 我再次为你的努力投票。我猜是因为他们觉得可以使用 Contains 来完成。
    【解决方案2】:

    当然 - 只需使用 Contains - 以 Northwind 为例:

    var qry = from cust in ctx.Customers
              where custIds.Contains(cust.CustomerID)
                 && regions.Contains(cust.Region)
              select cust; // or your custom projection
    

    【讨论】:

      【解决方案3】:

      嗯,你可以试试:

      var query = from dessert in db.Desserts
                  where appleIdentities.Contains(dessert.AppleIdentity)
                     && chocolateIdentities.Contains(dessert.ChocolateIdentity)
                     && iceCreamIdentities.Contains(dessert.IceCreamIdentity)
                  select new { dessert.Id, dessert.Name };
      

      我相信这没关系,尽管当列表变得足够大 IIRC 时它会失败。这对于列表和数组应该没问题。

      我不确定您的第三个查询 - 我认为您需要一个列表来记录每个单独的 Contains 调用。

      【讨论】:

        【解决方案4】:

        正如其他人所说,LinqToSql 会将Contains 翻译成IN

        有一些注意事项:

        • 此翻译适用于List&lt;T&gt;.Contains(),但不适用于IList&lt;T&gt;.Contains()。它适用于数组吗?我不知道。
        • 这种翻译会很高兴地翻译任意数量的元素 - 每个元素都成为一个 sql 参数。 SQL Server 2008 有大约 2000 个参数限制,如果您尝试使用太大的集合,会抛出 sql 异常
        • 当应用于字符串集合时,此转换将产生 nvarchar 参数。如果目标列是 varchar 并且您想在该列上使用索引,这可能是一个严重的问题。 Sql Server 将转换索引,而不是参数...这涉及读取和转换整个索引中的每个字符串。

        以下是您的对象列表问题的一些代码:

        List<int> someIDs = identities
           .Select(x => x.appleIdentity).ToList();
        List<string> someStrings = identities
           .Select(x => x.chokolateName).ToList();
        
        var query = db.Desserts.Where(d =>
          someIDs.Contains(d.AppleIdentity) &&
          someStrings.Contains(d.ChocolateName)
          )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-08
          相关资源
          最近更新 更多