我一直在讨论这个问题。有一些类似的案例,但解决方案并不适用于我的案例。
我有一个以字符串格式返回过滤器查询的方法。该方法具有不同数据类型的逻辑,设置正确的值,列名等。
string filterQuery = GetFilterQuery(params);
rows = rows.Where(filterQuery);
我的问题是我在数据库中有Nullable DateTime
,代码端有String
个表示。
我尝试过以下查询(目前String
表示可能有误):
"BirthDate.ToString() = \"16.2.2012 22:00:00\""
结果:类型'日期时间的方法?'无法访问
"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""
结果: LINQ to Entities无法识别方法' System.String ToString()'方法,此方法无法转换为商店表达式。
"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""
结果:'。'或'('预期
任何想法如何解决问题?
更新(添加了有关查询生成的更多源代码)
var filterQueries = query.GridFilteringOptions.filters
// remove filters that doesn't have all the required information
.Where(o => o.name != string.Empty && o.value != string.Empty && !string.IsNullOrEmpty(o.type))
// remove filters that are filtering other tables than current
.Where(o => o.table == tableName)
.Select(filter => filter.ResolveQuery()).ToList();
if (filterQuery.Any())
{
var filterQuery = string.Join(" And ", filterQueries);
rows = rows.Where(filterQuery);
}
这是一个类Filter,方法与此上下文相关
public string ResolveQuery()
{
if (type == "Int64")
{
return ResolveInteger();
}
else if(type == "String")
{
return ResolveString();
}
else if(type == "DateTime")
{
return ResolveDateTime();
}
else
{
return string.Empty;
}
}
private string ResolveDateTime()
{
DateTime result = new DateTime();
if (DateTime.TryParse(this.value, out result))
{
return string.Format("{0}.ToString() = \"{1}\"", this.name, result.ToUniversalTime());
}
return string.Empty;
}
private string ResolveString()
{
switch (@operator)
{
default:
return string.Format(@"{0}.StartsWith(""{1}"")", this.name, this.value);
}
}
private string ResolveInteger()
{
string tmp = this.name;
switch (@operator)
{
case -1:
return string.Empty;
case 0:
tmp += "<";
break;
case 1:
tmp += "=";
break;
case 2:
tmp += ">";
break;
default:
return string.Empty;
}
tmp += value;
return tmp;
}
答案 0 :(得分:2)
LINQ to Entities无法识别ToString()
方法。在将结果字符串插入查询之前,您必须对其进行评估。
要在您的问题中创建示例,您可以像这样处理它:
// "BirthDate.ToString() = \"16.2.2012 22:00:00\""
string birthdate = BirthDate.ToString();
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate);
// "BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""
string birthdate = BirthDate.Value.ToString();
string query = String.Format("{0} = \"16.2.2012 22:00:00\"", birthdate);
"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""
可能不起作用,因为LINQ to EF无法识别三元运算符(? :
)
修改:我从您的评论中了解到BirthDate
是表格中的一列,而不是变量。在这种情况下,您可以检索所有条目,将它们转换为列表,然后使用LINQ到这样的对象应用过滤器(尽管您必须相应地修改filterQuery
):
string filterQuery = GetFilterQuery(params);
var filteredRows = rows.ToList().Where(filterQuery);
未经测试:可以使用数据库的CONVERT
功能:
string query = "CONVERT(varchar(20), BirthDate) = \"16.2.2012 22:00:00\"";
答案 1 :(得分:0)
我的问题是我在数据库中有Nullable DateTime并且我有String表示 代码方。
为什么?
更改代码端,解析字符串表示并在LINQ查询中为其指定正确的对象。
“BirthDate.ToString()= \”16.2.2012 22:00:00 \“”
坏 - 如果你必须做字符串操作,AWLWAYS使用InvariantCulture。这段代码很脆弱,在任何其他国家都会破裂。
答案 2 :(得分:0)
我目前用try / catch块解决了这个问题。这增加了一些开销和丑陋,我宁愿找到替代品,但它确实非常有效:
try
{
// for strings and other non-nullables
records = records.Where(rule.field + ".ToString().Contains(@0)", rule.data);
}
catch (System.Linq.Dynamic.ParseException)
{
// null types
records = records.Where(rule.field + ".Value.ToString().Contains(@0)", rule.data);
}
注意:从输入变量(rule.field
和rule.data
)接受这些字段是危险的,并且可能会打开(困难的)盲SQL注入。可以根据值的白名单检查第一个值(rule.field
),以防止这种情况发生。