【问题标题】:C# MVC4 Linq - Filter table by either date or date + timeC# MVC4 Linq - 按日期或日期+时间过滤表
【发布时间】:2014-08-29 15:38:00
【问题描述】:

我有一个包含几列的表,我按列搜索 + 用户输入的字符串以过滤结果。但是,我无法让我的 DateTime 列正确过滤(其余所有工作)。我可以显示完全匹配的结果,但如果用户只输入一个没有时间的日期,我就没有结果。

预期结果是,如果用户输入 14/08 或 14/08/2014 或 14/08/2014 12:56:32,则应显示与输入的日期或日期和时间匹配的所有结果。

我的 Linq

var filterresults = from m in db.cd_CleardownCore
                            select m;

我的过滤器尝试 1:(仅完全匹配

DateTime datetime = Convert.ToDateTime(searchString);
string strDate = datetime.ToShortDateString();

filterresults = filterresults.Where(x => x.TimeStarted == datetime)

我的过滤器尝试 2:(检查列是否包含日期

filterresults = filterresults.Where(x => x.TimeStarted.ToString().Contains(strDate));

那么有人可以解释为什么尝试 2 不起作用吗?或者可以提出解决方案? + 如果我能提供任何使之更清楚的信息,请告诉我。

【问题讨论】:

  • 只是好奇你为什么要做包含而不是开始。但是,如果我是你我会调试这个的方式,就是看看 TimeStarted.ToString() 给你什么。这会让你知道哪里出了问题
  • 来自msdn.microsoft.com/en-us/library/k494fzbf(v=vs.110).aspx 它说 date.ToString() 以当前文化格式返回日期和时间。这是否可能意味着您的 TimeStarted.ToString() 正在返回“08/14/2014”?

标签: c# linq asp.net-mvc-4 datetime linq-to-entities


【解决方案1】:

您需要两个查询:

首先检查datetime 对象是否有除00:00:00 以外的时间,这意味着指定了某个时间部分,在这种情况下您需要精确比较,否则比较传递日期范围的字段,例如:

DateTime datetime = Convert.ToDateTime(searchString);
if (datetime.TimeOfDay != TimeSpan.Zero) //comparison with 00:00:00 time
{
    filterresults = filterresults.Where(x => x.TimeStarted == datetime);
}
else
{
    DateTime plusOneDateTime = datetime.AddDays(1).Date;
    filterresults = filterresults.Where(x => x.TimeStarted >= datetime.Date 
                                           && x.TimeStarted < plusOneDateTime);
}

您的查询失败的原因是在 LINQ to 实体中使用 ToString 会失败,因为没有可用的从 LINQ 表达式到基础数据源语言的转换(SQL)

还请记住,您与准确时间的比较可能不会返回任何结果,因为searchString 可能不包含存储在数据库中的准确时间。在这种情况下,您可以诉诸小时/分钟/秒的范围检查。

【讨论】:

  • +1。范围方法是正确的。为了澄清关于精度的最后一点,我建议 OP,而不是第一部分中显示的完全匹配,您应该投入更多的工作来根据给定的输入确定查询范围的起点和终点。例如,如果用户给出的值是14/08/2014 12:56,那么查询应该从14/08/2014 12:56:00(包括)运行到14/08/2014 12:57:00(不包括)。
  • 另外 - 注意文化差异。在不提供文化的情况下使用 Convert.ToDateTime 解析将使用 current 文化 - 这可能与用户的文化一致,也可能不符合。考虑到用户可能输入"01/02/2014",您需要确定是 2 月 1 日还是 1 月 2 日。
  • 谢谢 Habib,代码按照我在项目中的预期工作,您的解释很好。还要感谢 Matt,这让我对如何改进项目有了一些想法,因为在最终版本中迎合文化将很重要。
【解决方案2】:

日期时间匹配会很棘手,因为您接受的输入范围很广。

如果格式或多或少是固定的,您可能可以摆脱字符串匹配。

所以假设你总是接受 DD/MM/YYYY HH:MI:SS,你可以试试

filterresults = filterresults.ToArray().Where(x =&gt; x.TimeStarted.ToString("dd/MM/yyyy hh:mm:ss").IndexOf(strDate) &gt; -1));

您在这里所做的实质上是标准化您的比较基础,并且由于数据和时间具有不同的分隔符,因此简单的子字符串检查可以为您提供正确的结果。

所以假设TimeStarted14/08/2014 12:56:32

"14/08/2014 12:56:32".IndexOf("14/08") // matches
"14/08/2014 12:56:32".IndexOf("14/08/2014") // matches
"14/08/2014 12:56:32".IndexOf("14/08/2014 12:56:32") // matches

只要人们按以下顺序搜索日期的部分内容,此逻辑就会起作用:

DD
日/月
DD/MM/YYYY

等等。

如果用户输入 09 并且 09 表示日或月,则可能会产生歧义。但是,如果您的 UI 始终遵循规则,前 2 是天,后 2 是月,后 4 是年,依此类推,那么您就可以了。

另请注意,我正在执行 ToArray,因为 Linq2Entities 不理解 ToString

【讨论】:

  • ToArray 将拉下整个表并在内存中过滤,而您提供的格式字符串在 C# 中无效。
  • 修复了格式字符串。是的,这将导致整张桌子倒塌,但同样,它是可接受的还是不可接受的,取决于 OP 的情况。
【解决方案3】:

您想比较日期部分 - 这样做:

DateTime datetime = Convert.ToDateTime(searchString);


filterresults = filterresults.Where(x => x.TimeStarted.Date == datetime.Date)

您也可以使用ToString("d"),但这不是必需的。

【讨论】:

    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 2013-10-20
    • 2018-01-25
    • 1970-01-01
    • 2021-09-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多