动态 LINQ(到实体)其中具有可为空的 DateTime 列
一段时间以来,我一直在思考这个问题。有一些类似的案例,但解决方案不适用于我的案例。
我有一个以字符串格式返回过滤器查询的方法。该方法具有针对不同数据类型的逻辑,设置正确的值、列名等。
string filterQuery = GetFilterQuery(params);
rows = rows.Where(filterQuery);
我的问题是数据库中有 Nullable DateTime
,并且代码中有 String
表示形式边。
我已尝试以下查询(String
目前表示可能是错误的):
"BirthDate.ToString() = \"16.2.2012 22:00:00\""
结果:类型“DateTime?”上的方法无法访问
"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""
结果:LINQ to Entities 无法识别“System.String ToString()”方法,并且此方法无法转换为存储表达式。 em>
"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;
}
I have been banging my head on this problem for sometime. There are some similar cases, but the solutions weren't applicable on my case.
I have a method that returns filter query in string format. The method has logic for different data types, sets correct values, column names etc.
string filterQuery = GetFilterQuery(params);
rows = rows.Where(filterQuery);
My problem is that I have Nullable DateTime
in the database and I have String
representation in the code side.
I have tried following queries (String
representation might be wrong currently):
"BirthDate.ToString() = \"16.2.2012 22:00:00\""
Result: Methods on type 'DateTime?' are not accessible
"BirthDate.Value.ToString() = \"16.2.2012 22:00:00\""
Result: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""
Result: '.' or '(' expected
Any ideas how to solve the problem?
Update (more source code added about query generation)
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);
}
And here is a class Filter and methods are related to this context
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
LINQ to Entities 无法识别
ToString()
方法。在将结果字符串插入查询之前,您必须对其进行评估。要创建问题中的示例,您可以这样处理:
"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""< /code> 可能不起作用,因为 LINQ to EF 无法识别三元运算符 (
? :
)编辑:我从您的评论中了解到
BirthDate
是表中的一列,而不是变量。在这种情况下,您可以检索所有条目,将它们转换为列表,然后使用 LINQ to Objects 应用过滤器,如下所示(尽管您必须相应地修改filterQuery
):未经测试:< /strong> 可能可以使用数据库的
CONVERT
函数:LINQ to Entities doesn't recognize the
ToString()
method. You would have to evaluate it before inserting the resulting string into your query.To create the examples in your question you might handle it like this:
"BirthDate == null ? 1=1 : (DateTime)BirthDate.ToString() = \"16.2.2012 22:00:00\""
probably doesn't work because LINQ to EF doesn't recognize the ternary operator (? :
)Edit: I understand from your comment that
BirthDate
is a column in your table, not a variable. In this case you can retrieve all entries, convert them to a list and then apply the filter using LINQ to Objects like this (although you would have to modify yourfilterQuery
accordingly):Untested: It might be possible to use your database's
CONVERT
function:为什么?
更改代码端,解析字符串表示形式并在 LINQ 查询中为其提供正确的对象。
不好 - 如果你必须进行字符串操作,AWLWAYS 使用 InvariantCulture。该代码很脆弱,在任何其他国家/地区都会被破坏。
Why?
Change the code side, parse the string representation and give it the proper object in the LINQ query.
BAD - IF you have to do string manipulatzion, AWLWAYS use InvariantCulture. This code is fragile and will break in any other country.
我目前用 try/catch 块解决了这个问题。这增加了一些开销和丑陋,我宁愿找到替代方案,但它确实工作得非常可靠:
注意:从输入变量接受这些字段(
rule.field
和rule.data< /code>) 是危险的,可能会让您面临(困难的)盲目 SQL 注入。可以根据值白名单检查第一个值 (
rule.field
),以防止出现这种情况。I currently solve this with a try/catch block. That adds some overhead and ugliness that I would rather find an alternative for, but it does work very solidly:
Note: Accepting those fields from input variables (the
rule.field
andrule.data
) is dangerous, and may open you up to a (difficult) blind SQL Injection. The first value (rule.field
) can be checked against a whitelist of values, to prevent this.我知道我的答案有点晚了,但对于每个仍在同一情况下挣扎的人,您可以尝试此解决方案
这样,无论 BirthDate 是 DateTime 还是 DateTime?,它都可以工作。
最好先检查 BirthDate 是否不为 null
方法 .ToString() 适用于日期时间和可为空的日期时间
I know my answer is a bit late but for every one that is still struggling with the same case you can try this solution
This way it will work wether BirthDate is DateTime or DateTime?.
It is better to check if BirthDate is not null before
The method .ToString() works for both datetime and nullable dateTime