为什么我不能在LinQ查询中将可空的DateTime转换为字符串?

时间:2011-11-14 22:08:50

标签: linq datetime nullable

我正在尝试获取DateTime值,如果它不为null,则返回短时间字符串。我的查询如下所示: (TimeIn不可用,而TimeOut为NULLABLE)

    var times = from t in db.TimePostings
                where t.MemberID == member.MemberID
                select new
                {
                    Date = t.TimeIn.ToShortDateString(),
                    TimeIn = t.TimeIn.ToShortTimeString(),
                    TimeOut = t.TimeOut.HasValue ? t.TimeOut.Value.ToShortTimeString() : "-------"
                };
gvTimePostings.DataSource = times;
gvTimePostings.DataBind();

但是当我尝试使用错误数据绑定时失败:

  

无法翻译表达式'表(TimePosting)。其中(t =&gt;   (t.MemberID == Invoke(value(System.Func 1[System.String])))).Select(t => new <>f__AnonymousType8 4(Date = t.TimeIn.ToShortDateString(),TimeIn = t.TimeIn.ToShortTimeString(),TimeOut =   IIF(t.TimeOut.HasValue,(t.TimeOut ??   调用(值(System.Func`1 [System.DateTime的])))。ToShortTimeString(),   “-------”),Hours =“”))'进入SQL并且无法将其视为本地   表达

如果我尝试使用,我也会收到类似的错误:

TimeOut = t.TimeOut.HasValue ? Convert.ToDateTime(t.TimeOut).ToShortTimeString() : "-------"

但是,如果我将TimeOut属性更改为:

TimeOut = t.TimeOut.HasValue ? t.TimeOut.ToString() : "-------",

它工作正常,但不会像我想要的那样格式化时间(shortTimeString)。

这是怎么回事?

6 个答案:

答案 0 :(得分:9)

正如其他人所说,问题在于尝试将ToShortDateString等转换为SQL。幸运的是,这很容易解决:使用SQL获取数据,然后在.NET中格式

var timesFromDb = from t in db.TimePostings
                  where t.MemberID == member.MemberID
                  select new { t.TimeIn, t.TimeOut };

var times = from t in timesFromDb.AsEnumerable()
            select new
            {
                Date = t.TimeIn.ToShortDateString(),
                TimeIn = t.TimeIn.ToShortTimeString(),
                TimeOut = t.TimeOut.HasValue 
                                     ? t.TimeOut.Value.ToShortTimeString() 
                                     : "-------"
            };

此处对AsEnumerable()的调用基本上意味着,“停止尝试使用SQL处理查询;在LINQ to Objects中完成其余工作”。

答案 1 :(得分:6)

ToShortTimeString()在SQL中没有翻译。因此,将语句转换为单个SQL语句失败并抛出异常。

如果你将语句分成两个调用(一个用于检索数据而另一个用于创建投影),那么事情就可以了:

// must call ToList to force execution of the query before projecting
var results = from t in db.TimePostings
              where t.MemberID == member.MemberID
              select new { t.TimeIn, t.TimeOut };

var times = from t in results.AsEnumerable()
            select new
            {
                Date = t.TimeIn.ToShortDateString(),
                TimeIn = t.TimeIn.ToShortTimeString(),
                TimeOut = t.TimeOut.HasValue ? 
                    t.TimeOut.Value.ToShortTimeString() :
                    "-------"
            };

答案 2 :(得分:2)

你试过了吗?

TimeOut = t.TimeOut.HasValue ? t.TimeOut.ToString("d") : "-------",

这通常会给出DateTime的短格式。它是否有效将取决于它是否可以转换为SQL。

如果它不起作用,您必须将查询分为两部分。第一个获取数据,第二个获取数据。您必须将第一个查询转换为列表(.ToList())以强制SQL进行评估。

答案 3 :(得分:2)

简单来说,这个特定的linq提供商不支持它。

您的linq查询将转换为表达式树。由SQL Linq提供程序将此表达式树转换为SQL。可以理解的是,它没有能力翻译每一个.NET函数。

您的解决方案是通过调用ToArrayToList显式运行SQL,然后允许LinqToObjects处理其余的SQL。

   var times = from t in db.TimePostings
            where t.MemberID == member.MemberID
           select new { 
                        TimeIn = t.TimeIn,
                        TimeOut = t.TimeOut
                      };

   var timesFormated = times.ToArray()   // Runs the query - any further processing will be run in memory by the local .NET code
                        .Select(t => new {
                                           Date = t.TimeIn.ToShortDateString(),
                                           TimeIn = t.TimeIn.ToShortTimeString(),
                                           TimeOut = t.TimeOut.HasValue ? t.TimeOut.Value.ToShortTimeString() : "-------",
                                          Hours = ""                                               
                                         }
                                );

答案 4 :(得分:1)

您的查询由LINQ转换为针对您的数据库触发的SQL,并且显然无法将t.TimeOut.Value.ToShortTimeString()转换为SQL。

可能的解决方案是:

  1. 首先从数据库中获取数据(通过在LINQ查询上调用.ToList().ToArray()),将IQueryable<>转换为IEnumerable<>,然后为每个应用转换行取了。
  2. 使用一个视图,它接受原始表并使用SQL Server上的CONVERT()函数执行转换,并将其用作Linq-to-SQL类的源。这将是性能,但需要进行一些服务器端更改。

答案 5 :(得分:0)

我在vb.net的项目中遇到了同样的问题。 我发现的解决方案基于以下用途:

if(table.field.hasvalue, table.field.value.ToShortDateString, string.format("NULL"))

在这种情况下,如果所选字段(table.field)具有值,则将其转换为日期字符串,否则如果该字段没有值,则输出字段将填充字符串“NULL”