C# 将DateTime作为字符串比较到LINQ to Entities(';无法识别DateTime.parse(字符串)

C# 将DateTime作为字符串比较到LINQ to Entities(';无法识别DateTime.parse(字符串),c#,.net,linq,entity-framework,datetime,C#,.net,Linq,Entity Framework,Datetime,我正在使用C#、.NET Framework 4.0和实体框架代码首先开发一个WCF RESTful服务 我有这样一个类(表示数据库上的表): 我正试图做到这一点: DateTime fourDaysAgo = DateTime.Now.Date.AddDays(-4); var postLines = context.PostLines.Where(p => DateTime.Compare(DateTime.Parse(p.DateUtc), fourDaysAgo) &g

我正在使用C#、.NET Framework 4.0和实体框架代码首先开发一个WCF RESTful服务

我有这样一个类(表示数据库上的表):

我正试图做到这一点:

DateTime fourDaysAgo = DateTime.Now.Date.AddDays(-4);

var postLines = 
    context.PostLines.Where(p => DateTime.Compare(DateTime.Parse(p.DateUtc), fourDaysAgo) > 0).Include("Author");
但我得到了以下错误:

{System.NotSupportedException:LINQ to Entities无法识别无法转换为存储库表达式的方法“System.DateTime Parse(System.String)”。

我需要将
PostLine.DateUtc
作为字符串,因为我将在web服务上使用它,并将其作为JSON发送,所以最好将其存储为字符串

如果我使用
DateTime
type,我将在JSON响应中得到如下内容:

{
    "DateUtc": "/Date(1380924000000+0200)/",
    "Description": "post_1",
    "UserId": 1
}

您知道如何比较LINQ表达式上的字符串和日期时间吗?

我认为最好的方法是将属性一分为二

实体框架需要一个
DateTime
属性。这很有意义

对于序列化,您需要一个
string
属性。这也很有意义

但是,您试图为这两个属性使用一个属性,这没有意义,也没有必要

[DataContract]
public class PostLine
{
    ...

    public DateTime DateUtcAsDateTime { get; set; }

    [DataMember, NotMapped]
    public string DateUtcAsString {
        get { return DateUtcAsDateTime.ToString(); }
        set { DateUtcAsDateTime = DateTime.Parse(value); }
    }

    ...
}
现在,实体框架将使用
DateUtcAsDateTime
,而
DateUtcAsString
将被实体框架忽略,因为它具有
NotMapped
属性

另一方面,
DateUtcAsString
是这些属性中唯一具有
DataMember
属性的属性,因此应该是唯一序列化的属性

当然,如果需要,您可以将其中一个属性重命名回
DateUtc

更新:正如Matt Johnson所指出的,一个改进是以一种总是产生完全相同字符串的方式指定格式。这可以确保字符串不会因为代码被移动到另一台具有不同区域设置的服务器而更改

[DataMember, NotMapped]
public string DateUtcAsString {
    get { return DateUtcAsDateTime.ToString("o"); }
    set { DateUtcAsDateTime = DateTime.Parse(value, "o", null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); }
}
请注意,我使用的是
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal
,而不是他建议的
DateTimeStyles.RoundTripKind
,因为名称
DateUtc
强烈建议您始终使用UTC,而不是本地时间。而且我没有明确指定任何区域性,因为
“o”
格式已经独立于区域性


如果您的其他代码更容易处理,您可以使用
“r”
而不是
“o”
,具有相同的优点。

我认为最好的方法是将属性一分为二

实体框架需要一个
DateTime
属性。这很有意义

对于序列化,您需要一个
string
属性。这也很有意义

但是,您试图为这两个属性使用一个属性,这没有意义,也没有必要

[DataContract]
public class PostLine
{
    ...

    public DateTime DateUtcAsDateTime { get; set; }

    [DataMember, NotMapped]
    public string DateUtcAsString {
        get { return DateUtcAsDateTime.ToString(); }
        set { DateUtcAsDateTime = DateTime.Parse(value); }
    }

    ...
}
现在,实体框架将使用
DateUtcAsDateTime
,而
DateUtcAsString
将被实体框架忽略,因为它具有
NotMapped
属性

另一方面,
DateUtcAsString
是这些属性中唯一具有
DataMember
属性的属性,因此应该是唯一序列化的属性

当然,如果需要,您可以将其中一个属性重命名回
DateUtc

更新:正如Matt Johnson所指出的,一个改进是以一种总是产生完全相同字符串的方式指定格式。这可以确保字符串不会因为代码被移动到另一台具有不同区域设置的服务器而更改

[DataMember, NotMapped]
public string DateUtcAsString {
    get { return DateUtcAsDateTime.ToString("o"); }
    set { DateUtcAsDateTime = DateTime.Parse(value, "o", null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); }
}
请注意,我使用的是
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal
,而不是他建议的
DateTimeStyles.RoundTripKind
,因为名称
DateUtc
强烈建议您始终使用UTC,而不是本地时间。而且我没有明确指定任何区域性,因为
“o”
格式已经独立于区域性


如果您的其他代码更容易处理,可以使用
“r”
而不是
“o”
也有同样的好处。

我不知道你是如何实例化你的
DataContractJsonSerializer
。如果你直接实例化它…你可以传递一个
DataContractJsonSerializerSettings
,用一个
DateTimeFormat
来设置
DateTime
的序列化方式


如果您使用某个行为来实例化序列化程序,事情会稍微复杂一些。

我不知道您是如何实例化您的
DataContractJsonSerializer
。如果您直接实例化它…您可以传递一个
DataContractJsonSerializerSettings
,其中包含一个
DateTimeFormat
来设置de>DateTime被序列化


如果您使用行为来实例化序列化程序,那么事情会稍微复杂一些。

如果您真的想在将数据传输到客户端时为类使用字符串,那么您应该有一个单独的DTO类

然后,您可以使用AutoMapper之类的库,使用表达式将
PostLine
类映射到
PostLineDto

然而,接下来您将面临的问题是,您的
表达式将包含
Expression.MethodCall(DateTime.Parse)
,并且您必须插入一个
ExpressionVisitor
,它可以转换

p => p.DateUtc > DateTime.Parse("2013 Aug 1") - bool
进入


这是一个真正的难题。

如果您真的想在将数据传输到客户机时为类使用字符串,那么您应该有一个单独的DTO类

然后,您可以使用AutoMapper之类的库,使用表达式将
PostLine
类映射到
PostLineDto

然而,接下来你将面临的问题是