【问题标题】:load navigation properties with filter for Entity Framework 4.3使用 Entity Framework 4.3 的过滤器加载导航属性
【发布时间】:2012-06-27 14:26:02
【问题描述】:

几天前,我就使用 EF 映射两个类 MessageMessageStatusHistory 提出了 question。映射进展顺利,但我在Message 类中的导航属性StatusHistory 遇到了一些问题,该属性与MessageStatusHistory 对象相关联。我只为一个用户加载消息,并且只想要与该用户有关的状态。就像我想显示用户是否将消息标记为已读/未读以及何时。如果我使用如下的默认加载机制,它会加载与消息相关的所有历史记录,而与用户无关:

IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);

为了只过滤一个用户的历史记录,我尝试了以下技巧:

IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
        where m.MessageIdentifier == msgIdentifier
        select new Message
        {
            MessageIdentifier = m.MessageIdentifier,
            /*OTHER PROPERTIES*/
            StatusHistory = m.StatusHistory
                             .Where(x => x.UserId == userId).ToList()
        };

return q.ToList();//THROWING ERROR ON THIS LINE

我收到错误:

The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ 
to Entities query.

我也尝试过评论StatusHistory = m.StatusHistory.Where(x =&gt; x.UserId == userId).ToList(),但没有帮助。

请帮助我获取过滤后的 StatusHistory 的消息。

编辑:- 上面是用这个代码解决的:

var q = from m in _repository.DBSet.Include("Histories")
        where m.MessageIdentifier == id
        select new {
                     m.Id,/*OTHER PROPERTIES*/
                     Histories = m.Histories.Where(x => 
                                   x.SenderId == userId).ToList()
                   };

var lst = q.ToList();
return lst.Select(m => new Message{
           Id = m.Id, MessageIdentifier = m.MessageIdentifier, 
           MessageText = m.MessageText, Replies = m.Replies, 
           ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId = 
           m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
       }).ToList();

但如果我尝试在邮件中回复:

from m in _repository.DBSet.Include("Replies").Include("Histories")

我在使用q.ToList() for Histories = m.Histories.Where(x=&gt; x.SenderId == userId).ToList() 将查询转换为列表时出错。

【问题讨论】:

  • 这不是 StatusHistory。请参阅例外情况:您不能在实体查询中创建实体对象。您必须创建镜像类型或匿名类型。

标签: entity-framework-4 navigation-properties


【解决方案1】:

关于您的 EDIT 部分:您不能在投影中使用 ToList(),只需将其保留为 IEnumerable&lt;T&gt; 并在构造 Message 时转换为 List&lt;T&gt;。您也不需要创建两个列表对象,您可以使用 AsEnumerable() 从 LINQ to Entities 查询切换到 LINQ to Objects(第二个 Select):

var list = (from m in _repository.DBSet
            where m.MessageIdentifier == id
            select new {
                // ...
                Histories = m.Histories.Where(x => x.SenderId == userId)
            })
            .AsEnumerable() // database query is executed here
            .Select(m => new Message {
                // ...
                Histories = m.Histories.ToList(),
                // ...
            }).ToList();

return list;

请注意,当您将投影与 select 一起使用时,Include 无效。您需要将要包含的属性作为投影的一部分 - 正如您对 select new { Histories.... 所做的那样。

【讨论】:

  • 感谢您的帮助。只是一个小问题:如果我只有.Include("Histories").Include("Replies") 也在查询中,为什么m.Histories.Where(x=&gt;x.SenderId == userId).ToList() 工作?
  • @TheVillageIdiot:你确定第二个Include 会有所作为吗?老实说,我希望在投影中使用ToList() 永远不会起作用,无论您是否有Include 以及有多少。它应该总是抛出臭名昭著的“......无法将'ToList'翻译成商店表达式......”异常。
  • 是的,你是对的。它也在那里抛出异常。我把另一种方法误认为是这个方法(ToList)。
猜你喜欢
  • 2017-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多