LINQ to Entities不支持指定的类型成员'Offset'

时间:2013-11-15 09:34:19

标签: c# linq

我在下一个代码运行时遇到异常:

 var fbPost = db.FacebookStatusUpdates
         .Where(f => 
               f.FacebookUpdateTime - f.ClientTime.Offset <= 
               DateTimeOffset.Now.UtcDateTime - ConvertTimeSpan(f.Offset) &&
               f.Status == FacebookNotificationStatus.Active &&
               f.Alarm.User.FbStatus == true).ToList();

异常消息

  

LINQ to Entities不支持指定的类型成员'Offset'。只要   初始化器,实体成员和实体导航属性是   支撑。

我的模特:

 public class FacebookStatusUpdate
 {
    public long Id { get; set; }
    public DateTime FacebookUpdateTime { get; set; }
    public string PostId { get; set; }
    public DateTime? FacebookPostTime { get; set; }
    public DateTimeOffset ClientTime { get; set; }
    public int Offset { get; set; }

    public virtual FacebookNotificationStatus Status { get; set; }
    public virtual Alarm Alarm { get; set; }
}

有人能帮助我吗?

5 个答案:

答案 0 :(得分:6)

当您使用LINQ to Entities时,您需要记住您的查询将被转换为TSQL - 如果Offset是自定义类型,那么EF不知道如何将其转换为SQL。

如果您可以将查询转换为LINQ to Objects,即

,您当然可以完成此工作
 var fbPost = db.FacebookStatusUpdates
     .Where(f => f.Status == FacebookNotificationStatus.Active &&
                 f.Alarm.User.FbStatus == true)
     .AsEnumerable() // convert from L2E to L2O
     .Where(f => f.FacebookUpdateTime - f.ClientTime.Offset <= 
           DateTimeOffset.Now.UtcDateTime - ConvertTimeSpan(f.Offset))
     .ToList();

在调用AsEnumerable()之后,查询的其余部分是LINQ to Objects,它们了解Offset / ConvertToTimespan代码。只是为了澄清,AsEnumerable()不会实现您的查询正确方式 - 您仍然会延迟加载。但是,在AsEnumerable()完成客户端之后的任何进一步查询时,都不再与数据库进行交互。

使用L2E时,最好坚持使用受支持的primitive types

答案 1 :(得分:1)

我怀疑这与您无法在Linq中直接使用标准C#方法和属性这一事实有关,因为db.FacebookStatusUpdates中的数据最初可能无法加载。换句话说:该属性无法转换为SQL。

如果我的理解是正确的,这可能会为您提供解决方案:

var fbPost = db.FacebookStatusUpdates
              .ToList() // <-- Forces evaluation/data retrieval!
              .Where(f => 
                   f.FacebookUpdateTime - f.ClientTime.Offset <= 
                   DateTimeOffset.Now.UtcDateTime - ConvertTimeSpan(f.Offset) &&
                   f.Status == FacebookNotificationStatus.Active &&
                   f.Alarm.User.FbStatus == true).ToList();

这将在尝试呼叫ClientTime.Offset之前将数据加载到列表中,从而允许您进行该呼叫。

但是,在应用Where() - 过滤之前,所有数据都已加载。我想你必须根据你的背景和其他要求决定这是否可以接受,或者你是否需要寻找其他更好的解决方案。

答案 2 :(得分:1)

以下代码可以替换Linq to Entities查询中的a.MyDate.Offset

SqlFunctions.DatePart("TZoffset", a.MyDate)

请记住,这与SqlServer一起工作。

答案 3 :(得分:0)

问题在于您无法直接访问DateTimeOffset.Offset属性(f.ClientTime.Offset),就像您无法直接在Linq中访问实体的DateTime.Year属性一样 - 它可以不会直接翻译成商店表达。

我不知道你的f.FacebookUpdateTime - f.ClientTime.Offset <= DateTimeOffset.Now.UtcDateTime - ConvertTimeSpan(f.Offset)应该做什么,但你可以看一下静态SqlFunctions类来处理一些常见的日期操作函数,比如SqlFunctions.DateDiff()可以用。

替换整个表达式

另外,您使用的是EF6吗?否则你也必须将你的枚举投射到int

答案 4 :(得分:0)

您可以将查询分为两部分。

var fbPost_DBQuery = db.FacebookStatusUpdates
     .Where(f => f.Status == FacebookNotificationStatus.Active &&
                 f.Alarm.User.FbStatus == true).ToList();

fbPost_MemoryQuery = fbPost_DBQuery
     .Where(f => f.FacebookUpdateTime - f.ClientTime.Offset <= 
           DateTimeOffset.Now.UtcDateTime - ConvertTimeSpan(f.Offset))
     .ToList();

fbPost_DBQuery将从数据库中查询更多信息,然后在fbPost_MemoryQuery中进行过滤。但它会奏效。