林克 .其中()问题“无法确定条件表达式的类型”

本文关键字:表达式 条件 类型 无法确定 其中 问题 林克 | 更新日期: 2023-09-27 18:37:26

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

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,那么我们在没有 d.Service == site 参数的情况下执行.Where搜索。否则,除了查询的其余部分外,还会使用服务参数。这可能吗?

林克 .其中()问题“无法确定条件表达式的类型”

如果要

在满足条件时向查询添加其他筛选器,则该构造应位于查询本身之外,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()
    });

如果三元运算符"在"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() 
                    }); 

分解表达式将使您更好地可视化逻辑。

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);
}

从您的代码外观来看,在我看来,您正在使用实体框架进行查询。如果是这样,则不允许使用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)都采用延迟执行(有关延迟执行方法与立即执行方法的列表,请参见此处),这意味着只有一个查询将发送到您的数据库以进行最终data,并且仅在您以某种方式实际使用该变量时。

你的语法是错误的

 .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)