条件Linq查询

时间:2008-08-14 15:20:27

标签: c# linq linq-to-sql .net-3.5

我们正在研究日志查看器。该用户可以选择按用户,严重程度等进行过滤。在Sql中我会添加到查询字符串,但我想用Linq来做。我怎样才能有条件地添加where-clause?

13 个答案:

答案 0 :(得分:149)

如果您只想过滤某些标准,请执行以下操作

var logs = from log in context.Logs
           select log;

if (filterBySeverity)
    logs = logs.Where(p => p.Severity == severity);

if (filterByUser)
    logs = logs.Where(p => p.User == user);

这样做可以使Expression树完全符合您的要求。这样,创建的SQL将完全符合您的需求而且不会少。

答案 1 :(得分:21)

如果需要基于列表/数组进行过滤,请使用以下命令:

    public List<Data> GetData(List<string> Numbers, List<string> Letters)
    {
        if (Numbers == null)
            Numbers = new List<string>();

        if (Letters == null)
            Letters = new List<string>();

        var q = from d in database.table
                where (Numbers.Count == 0 || Numbers.Contains(d.Number))
                where (Letters.Count == 0 || Letters.Contains(d.Letter))
                select new Data
                {
                    Number = d.Number,
                    Letter = d.Letter,
                };
        return q.ToList();

    }

答案 2 :(得分:20)

我最后使用了类似于Daren的答案,但使用了一个IQueryable界面:

IQueryable<Log> matches = m_Locator.Logs;

// Users filter
if (usersFilter)
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text);

 // Severity filter
 if (severityFilter)
     matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);

 Logs = (from log in matches
         orderby log.EventTime descending
         select log).ToList();

在点击数据库之前构建查询。该命令直到最后的.ToList()才会运行。

答案 3 :(得分:14)

当谈到有条件的linq时,我非常喜欢过滤器和管道模式 http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

基本上,您为每个过滤器案例创建一个扩展方法,该过滤器案例包含IQueryable和参数。

public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
    return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}

答案 4 :(得分:4)

另一个选择是使用像PredicateBuilder讨论的here之类的东西。 它允许您编写如下代码:

var newKids  = Product.ContainsInDescription ("BlackBerry", "iPhone");

var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
                  .And (Product.IsSelling());

var query = from p in Data.Products.Where (newKids.Or (classics))
            select p;

请注意,我只使用它来使用Linq 2 SQL。 EntityFramework不实现Expression.Invoke,这是此方法工作所必需的。我对此问题有疑问here

答案 5 :(得分:3)

这样做:

bool lastNameSearch = true/false; // depending if they want to search by last name,

where声明中有这个:

where (lastNameSearch && name.LastNameSearch == "smith")

表示在创建最终查询时,如果lastNameSearchfalse,则查询将完全省略任何用于姓氏搜索的SQL。

答案 6 :(得分:3)

我用扩展方法解决了这个问题,它允许在流利的表达式中间有条件地启用LINQ。这样就无需使用if语句来拆分表达式。​​

.If()扩展方法:

public static IQueryable<TSource> If<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Func<IQueryable<TSource>, IQueryable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

这允许您执行以下操作:

return context.Logs
     .If(filterBySeverity, q => q.Where(p => p.Severity == severity))
     .If(filterByUser, q => q.Where(p => p.User == user))
     .ToList();

这里还有一个IEnumerable<T>版本,它将处理大多数其他LINQ表达式:

public static IEnumerable<TSource> If<TSource>(
    this IEnumerable<TSource> source,
    bool condition,
    Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

答案 7 :(得分:1)

这不是最漂亮的东西,但你可以使用lambda表达式并可选地传递你的条件。在TSQL中,我做了很多以下的操作来使参数可选:

  

WHERE Field = @FieldVar或@FieldVar IS NULL

您可以使用以下lambda(检查身份验证的示例)复制相同的样式:

  

MyDataContext db = new MyDataContext();

     

void RunQuery(字符串param1,字符串param2,int?param3){

     
    

Func checkUser = user =&gt;

         
      

((param1.Length&gt; 0)?user.Param1 == param1:1 == 1)&amp;&amp;

             

((param2.Length&gt; 0)?user.Param2 == param2:1 == 1)&amp;&amp;

             

((param3!= null)?user.Param3 == param3:1 == 1);

    
         

用户foundUser = db.Users.SingleOrDefault(checkUser);

  
     

}

答案 8 :(得分:1)

我最近有类似的要求,最终在他的MSDN中找到了这个。 CSharp Samples for Visual Studio 2008

下载的DynamicQuery示例中包含的类允许您在运行时以以下格式创建动态查询:

var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");

使用它可以在运行时动态构建查询字符串并将其传递给Where()方法:

string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; 
var q = from c in db.Customers.Where(queryString, null)
        orderby c.CompanyName
        select c;

答案 9 :(得分:0)

只需使用C#&amp;&amp;操作者:

var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")

编辑:啊,需要仔细阅读。您想知道如何有条件地添加其他条款。在那种情况下,我不知道。 :)我可能会做的只是准备几个查询,然后执行正确的查询,具体取决于我最终需要的内容。

答案 10 :(得分:0)

您可以使用外部方法:

var results =
    from rec in GetSomeRecs()
    where ConditionalCheck(rec)
    select rec;

...

bool ConditionalCheck( typeofRec input ) {
    ...
}

这可行,但不能分解为表达式树,这意味着Linq to SQL将针对每条记录运行检查代码。

可替换地:

var results =
    from rec in GetSomeRecs()
    where 
        (!filterBySeverity || rec.Severity == severity) &&
        (!filterByUser|| rec.User == user)
    select rec;

这可能适用于表达式树,这意味着Linq to SQL将被优化。

答案 11 :(得分:0)

嗯,我认为你可以将过滤条件放入Predicates的通用列表中:

    var list = new List<string> { "me", "you", "meyou", "mow" };

    var predicates = new List<Predicate<string>>();

    predicates.Add(i => i.Contains("me"));
    predicates.Add(i => i.EndsWith("w"));

    var results = new List<string>();

    foreach (var p in predicates)
        results.AddRange(from i in list where p.Invoke(i) select i);               

这导致包含“我”,“meyou”和“mow”的列表。

你可以通过在一个完全不同的函数中使用谓词对所有谓词进行foreach来优化它。

答案 12 :(得分:0)

您可以创建和使用此扩展方法

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}