LINQ <where>在C#中有条件?

时间:2019-03-15 09:59:46

标签: c# linq

是否可以将LINQ WHERE与条件布尔值一起使用,如果为false,则跳过。我的代码示例如下:-

var filters = ListResponse.filter.Where(a => a.FLRefID == EvtID).ToList();
foreach(var tofilter in filters)
{
    if (tofilter == null)
        continue;
    // The value in tofilter can be empty
    bool bFilterID = string.IsNullOrEmpty(tofilter.FLEventID);
    bool bFilterText = string.IsNullOrEmpty(tofilter.FLText);
    bool bFilterSource = string.IsNullOrEmpty(tofilter.FLSource);
    bool bFilterLevel = string.IsNullOrEmpty(tofilter.FLLevel);

    // Here in LINQ where I want to filter
    // EventDetails is List of Event Viewer Collection.
    var logs = EventDetails.Where(ax => bFilterID ? (ax.EventID == tofilter.FLEventID) | bFilterText ? (ax.EventMessage.Contains(tofilter.FLText)) | bFilterSource ? (ax.EventSourceName == tofilter.FLSource) | bFilterLevel ? (ax.Level == tofilter.FLLevel));
    string json = JsonConvert.SerializeObject(logs);
}

比方说,USER选择了他们要过滤的ID=1, SourceName=Application,其余的为空。如果使用bFilterID = true,然后使用ax.EventID == tofilter.FLEventID,如何在LINQ中添加条件。如果为False(用户未设置),它将跳过条件。过滤器可以是动态的,但必须至少有1个条件才能由USER设置。

我实际上不确定我要搜索的内容有哪些关键字,因为我不知道它是否存在。

更新: 我有Mik的测试答案,也有npo的答案。

> 18-03-2019 10:30:17.876405 [INFO] Time taken NPO 1: 00:00:00.0705490
> 18-03-2019 10:30:17.889374 [INFO] Time taken NPO 2: 00:00:00.0123487
> 18-03-2019 10:30:17.903334 [INFO] Time taken MIK:   00:00:00.0146780
> 
> 18-03-2019 10:30:17.947219 [INFO] Time taken NPO 1: 00:00:00.0435493
> 18-03-2019 10:30:17.977139 [INFO] Time taken NPO 2: 00:00:00.0297257
> 18-03-2019 10:30:17.981127 [INFO] Time taken MIK:   00:00:00.0036274
> 
> 18-03-2019 10:30:28.536724 [INFO] Time taken NPO 1: 00:00:00.2011405
> 18-03-2019 10:30:28.596560 [INFO] Time taken NPO 2: 00:00:00.0594285
> 18-03-2019 10:30:28.634464 [INFO] Time taken MIK:   00:00:00.0376055

3 个答案:

答案 0 :(得分:6)

这就是我的做法:

IQueryable<EventDetails> res = EventDetails;

if( !string.IsNullOrEmpty(tofilter.FLEventID) )
  res = res.Where(ax => ax.EventID == tofilter.FLEventID); 

if( !string.IsNullOrEmpty(tofilter.FLText) )
  res = res.Where(ax => ax.EventMessage.Contains(tofilter.FLText));

if( !string.IsNullOrEmpty(tofilter.FLSource) )
  res = res.Where(ax => ax.EventSourceName == tofilter.FLSource);

if( !string.IsNullOrEmpty(tofilter.FLLevel) )
  res = res.Where(ax => ax.Level == tofilter.FLLevel);

string json = JsonConvert.SerializeObject(res);

它会生成多个子查询,但是我不认为存在性能问题,并且可读性更高。

顺便说一句,我颠倒了您的IsNullOrEmpty测试,因为在您的代码中,您仅对空字符串进行过滤...

答案 1 :(得分:2)

您可以编写扩展方法来有条件地应用过滤器:

    new Chart(document.getElementById("radar-chart"), {
type: 'radar',
data: {
    labels: ["SQL", "CSS", "HTML"],
    datasets: [
        {
            label: "Scripting",
            fill: true,
            backgroundColor: "rgba(255,215,0,0.2)",
            borderColor: "rgba(255,215,0,1)",
            pointBorderColor: "#ffe100",
            pointBackgroundColor: "rgba(255,215,0,1)",
            data: [7.77,8.2,6.5]
        },
    ]
},

options: {
    title: {
        display: true,
        text: 'Scripting skill'
    }
}
    });

您的查询将变为:

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

答案 2 :(得分:1)

尝试一下

var filters = ListResponse.filter.Where(a => a.FLRefID == EvtID).ToList();
foreach(var tofilter in filters)
{
    if (tofilter == null)
        continue;
    // The value in tofilter can be empty
    bool bFilterID = string.IsNullOrEmpty(tofilter.FLEventID);
    bool bFilterText = string.IsNullOrEmpty(tofilter.FLText);
    bool bFilterSource = string.IsNullOrEmpty(tofilter.FLSource);
    bool bFilterLevel = string.IsNullOrEmpty(tofilter.FLLevel);
    if(new bool[]{bFilterID, bFilterText, bFilterSource, bFilterLevel}.All(z=>!z)) continue // continue when no filters were set like you wanted


    var logs = EventDetails.Where(ax => (bFilterID ? (ax.EventID == tofilter.FLEventID) : true ) || (bFilterText ? (ax.EventMessage.Contains(tofilter.FLText): true) || (bFilterSource ? (ax.EventSourceName == tofilter.FLSource) : true) || (bFilterLevel ? (ax.Level == tofilter.FLLevel) : true));
    string json = JsonConvert.SerializeObject(logs);
}

但是对于这种情况,最好使用谓词

这里是一个例子:

谓词构建器只是构建谓词的助手 可以在这里找到:Predicates

public static class PredicateBuilder
{
  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  public static Expression<Func<T, bool>> False<T> () { return f => false; }

  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  }

  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  }
}

针对您的情况,您可以执行以下操作

 var filters = ListResponse.filter.Where(a => a.FLRefID == EvtID).ToList();
    foreach(var tofilter in filters)
    {
        if (tofilter == null)
            continue;
        // The value in tofilter can be empty
        bool bFilterID = string.IsNullOrEmpty(tofilter.FLEventID);
        bool bFilterText = string.IsNullOrEmpty(tofilter.FLText);
        bool bFilterSource = string.IsNullOrEmpty(tofilter.FLSource);
        bool bFilterLevel = string.IsNullOrEmpty(tofilter.FLLevel);
        if(new bool[]{bFilterID, bFilterText, bFilterSource, bFilterLevel}.All(z=>!z)) continue // continue when no filters were set like you wanted

var predicate = PredicateBuilder.False<EventDetails> ();
if(bFilterID) predicate= predicate.Or(ax => ax.EventID == tofilter.FLEventID);
if(bFilterText) predicate= predicate.Or(ax => ax.EventMessage.Contains(tofilter.FLText));
if(bFilterSource) predicate= predicate.Or(ax => ax.EventSourceName == tofilter.FLSource);
if(bFilterLevel) predicate= predicate.Or(ax => ax.Level == tofilter.FLLevel);

        var logs = EventDetails.Where(predicate.Compile());
        string json = JsonConvert.SerializeObject(logs);
    }