linq .Where()问题"条件表达式的类型无法确定"

时间:2015-01-14 15:48:56

标签: c# linq

我希望能够在Linq查询中传递不同的变量,具体取决于字符串是否为空。

string site = null;
int q = a number;

var data = db.tbl_table12345
             .Where(site == null
                      ? d => d.stuff_id == org 
                             && d.Date.Month == q
                             && d.Date.Year == year 
                             && d.Q1 != (int?)null
                      : d => d.stuff_id == org
                             && d.Service == site
                             && d.Date.Month == q 
                             && d.Date.Year == year
                             && d.Q1 != (int?)null)
             .GroupBy(d => d.Q1)
             .Select(d => new
                          {
                              q1 = d.Key,
                              total = d.Count()
                          });

因此,在上面的示例中site == null,我们会在没有.Where参数的情况下执行d.Service == site搜索。否则,除了查询的其余部分之外,还使用service参数。这可能吗?

5 个答案:

答案 0 :(得分:4)

如果要在满足条件时向查询添加额外的过滤器,那么该构造应该在查询本身之外,LINQ很容易做到:

var query = db.tbl_table12345
    .Where(d => d.stuff_id == org
                    && d.Date.Month == q
                    && d.Date.Year == year
                    && d.Q1 != (int?)null);
if (site != null)
    query = query.Where(d => d.Service == site);
var data = query.GroupBy(d => d.Q1)
    .Select(d => new
    {
        q1 = d.Key,
        total = d.Count()
    });

答案 1 :(得分:1)

如果三元运算符在lambda“内部”,它应该可以工作。

string site = null;
int q = a number;

var data = db.tbl_table12345
             .Where(d => site == null 
                    ? d.stuff_id == org 
                      && d.Date.Month == q 
                      && d.Date.Year == year 
                      && d.Q1 != (int?)null 
                    : d.stuff_id == org 
                      && d.Service == site 
                      && d.Date.Month == q 
                      && d.Date.Year == year 
                      && d.Q1 != (int?)null)
             .GroupBy(d => d.Q1)
             .Select(d => new 
                    { 
                         q1 = d.Key,
                         total = d.Count() 
                    }); 

答案 2 :(得分:1)

分解表达式可以让您更好地可视化您的逻辑。

string site = null;
int month = a number;

Expression<Func<SomeType, bool>> nullExpression =
    d => d.stuff_id == org 
         && SqlFunctions.DatePart("MONTH", d.Date) == month
         && SqlFunctions.DatePart("YEAR", d.Date) == year
         && d.Q1 != (int?)null;

Expression<Func<SomeType, bool>> notNullExpression =
    d => d.stuff_id == org
         && SqlFunctions.DatePart("MONTH", d.Date) == month
         && SqlFunctions.DatePart("YEAR", d.Date) == year
         && d.Q1 != (int?)null
         && d.Service == site;

var expression = site == null ? nullExpression : notNullExpression

var data = db.tbl_table12345
             .Where(expression)
             .GroupBy(d => d.Q1)
             .Select(d => new { q1 = d.Key, total = d.Count() });

或使用表达式树:

var expression = BuildWhere(org, month, year, site);
var data = db.tbl_table12345
         .Where(expression)
         .GroupBy(d => d.Q1)
         .Select(d => new { q1 = d.Key, total = d.Count() });

这是一种方法,可以建立你的Expression<Func<SomeType, bool>

public Expression BuildWhere(int org, int month, int year, string service = null)
{
    var datePartMethod =
        typeof(SqlFunctions)
            .GetMethod("DatePart",
                       new[]
                       {
                           typeof(string),
                           typeof(DateTime?)
                       });

    // Variable d
    var variable =
        Expression.Variable(typeof(SomeType));

    var orgConstant =
        Expression.Constant(org);
    // d.stuff_id
    var stuffId =
        Expression.Property(variable, "stuff_id");

    // d.stuff_id == org
    var stuffIdEquals =
        Expression.Equal(stuffId, orgConstant);

    // d.Date cast into Nullable DateTime
    var date =
        Expression.Convert(
            Expression.Property(variable, "Date"),
            typeof(DateTime?));

    var monthPartConstant =
        Expression.Constant("MONTH");
    // month cast to nullable int
    var monthConstant =
        Expression.Convert(
            Expression.Constant(month),
            typeof(int?));
    var yearPartConstant =
        Expression.Constant("YEAR");
    // year cast to nullable int
    var yearConstant =
        Expression.Convert(
            Expression.Constant(year),
            typeof(int?));

    // SqlFunctions.DatePart("MONTH", d.Date)
    var invokeDatePartMonthPart =
        Expression.Call(
            datePartMethod,
            monthPartConstant,
            date);
    // SqlFunctions.DatePart("YEAR", d.Date)
    var invokeDatePartYearPart =
        Expression.Call(
            datePartMethod,
            yearPartConstant,
            date);

    // SqlFunctions.DatePart("MONTH", d.Date) == month
    var dateMonthEquals =
        Expression.Equal(
            invokeDatePartMonthPart,
            monthConstant);

    // SqlFunctions.DatePart("MONTH", d.Date) == year
    var dateYearEquals =
        Expression.Equal(
            invokeDatePartYearPart,
            yearConstant);

    // d.Q1
    var q1 = Expression.Property(variable, "Q1");
    var nullConstant =
        Expression.Constant((int?) null);
    // d.Q1 != (int?) null
    var q1NotEquals =
        Expression.NotEqual(
            q1,
            nullConstant);

    // d.stuff_id == org
    // && SqlFunctions.DatePart("MONTH", d.Date) == month
    // && SqlFunctions.DatePart("YEAR", d.Date) == year
    // && d.Q1 != (int?) null
    var andExpression = 
        Expression.AndAlso(stuffIdEquals,
            Expression.AndAlso(dateMonthEquals,
            Expression.AndAlso(dateYearEquals,
                q1NotEquals)));

    // Add d.Service only when not null
    if(service != null)
    {
        // d.Service
        var serviceConstant =
            Expression.Constant(service);
        var serviceProperty =
            Expression.Property(
                variable,
                "Service");

        // d.Service == service
        var serviceEquals =
            Expression.Equal(
                serviceProperty,
                serviceConstant);

        andExpression =
            Expression.AndAlso(
                andExpression,
                serviceEquals);
    }

    // Creates a lambda to represent the logic
    var parameter = Expression.Parameter(typeof(SomeType));
    return Expression
        .Lambda<Func<SomeType, bool>>(
            andExpression,
            parameter);
}

答案 3 :(得分:0)

您的语法错误

 .Where(d => site == null 
          ? d.stuff_id == org 
                 && d.Date.Month == q && d.Date.Year == year 
                 && d.Q1 != (int?)null
          : d.stuff_id == org
                 && d.Service == site && d.Date.Month == q 
                 && d.Date.Year == year && d.Q1 != (int?)null)

答案 4 :(得分:0)

从您的代码看起来的方式来看,我认为您正在使用Entity Framework进行查询。如果是这样,那么你不允许d.Date.Month这样的东西,因为EF不知道如何正确地将它转换成SQL本身。您需要使用SqlFunctions类(特别是DatePart方法)才能使此查询正常工作。使用@ Servy的解决方案作为开始:

var query = db.tbl_table12345
    .Where(d => d.stuff_id == org
             && SqlFunctions.DatePart("MONTH", d.Date) == q
             && SqlFunctions.DatePart("YEAR", d.Date) == year
             && d.Q1 != (int?)null);
if (site != null)
    query = query.Where(d => d.Service == site);

var data = query.GroupBy(d => d.Q1)
    .Select(d => new
    {
        q1 = d.Key,
        total = d.Count()
    });

使用此方法的另一个好理由是上面的所有LINQ子句(WhereGroupBySelect都使用了延迟执行(请参阅here延迟与立即执行方法的列表),这意味着只有一个查询将被发送到您的数据库以用于最终data,并且只有当您以某种方式实际使用该变量时才会发送。