linq .Where() 问题 "Type of condition expression cannot be determined"
linq .Where() issue "Type of condition expression cannot be determined"
我希望能够根据字符串是否为 null 在 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
那么我们执行一个没有 d.Service == site
参数的 .Where
搜索。否则除了查询的其余部分之外,还会使用服务参数。这可能吗?
你的语法错误
.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)
如果三元运算符是 "inside" 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() });
这里有一个方法可以建立你的 where 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);
}
如果您想在满足条件时向查询添加额外的过滤器,那么该构造应该在查询本身之外,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()
});
从代码的外观来看,我认为您正在使用 Entity Framework 进行查询。如果是这样,则不允许使用 d.Date.Month
之类的内容,因为 EF 本身不知道如何将其正确转换为 SQL。您需要使用 SqlFunctions
class(特别是 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 子句(Where
、GroupBy
和 Select
)都采用延迟执行(参见 here 用于延迟执行与立即执行方法的列表),这意味着只有一个查询将发送到您的数据库以进行最终 data
,并且仅当您以某种方式实际使用该变量时。
我希望能够根据字符串是否为 null 在 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
那么我们执行一个没有 d.Service == site
参数的 .Where
搜索。否则除了查询的其余部分之外,还会使用服务参数。这可能吗?
你的语法错误
.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)
如果三元运算符是 "inside" 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() });
这里有一个方法可以建立你的 where 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);
}
如果您想在满足条件时向查询添加额外的过滤器,那么该构造应该在查询本身之外,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()
});
从代码的外观来看,我认为您正在使用 Entity Framework 进行查询。如果是这样,则不允许使用 d.Date.Month
之类的内容,因为 EF 本身不知道如何将其正确转换为 SQL。您需要使用 SqlFunctions
class(特别是 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 子句(Where
、GroupBy
和 Select
)都采用延迟执行(参见 here 用于延迟执行与立即执行方法的列表),这意味着只有一个查询将发送到您的数据库以进行最终 data
,并且仅当您以某种方式实际使用该变量时。