LINQ包含和Projection

时间:2015-07-24 15:09:21

标签: linq entity-framework

我有一些类定义具有关系的实体

Account 
has many Conversations [IEnumerable<Conversation> Conversations]

Conversation 
has many Participants [IEnumerable<Account> Participants]
has many Messages [IEnumerable<Message> Messages]

Message 
has one Sender [Account Sender]
has one Conversation [Conversation Conversation]

我正在尝试编写一个LINQ查询,该查询返回按日期排序的对话列表,并包含相关的参与者和消息。

public async Task<List<Conversation>> FindAllByAccountIdAsync(Int32 id)
{
    return await _Db.Conversations
         .Where(c => c.Participants.Any(p => p.AccountId == id))
         .Include(c => c.Participants)
         .Include(c => c.Messages)
         .ToListAsync();
}

这可以完成工作,但包含了我真正不需要的大量数据。

public async Task<List<Conversation>> FindAllByAccountIdAsync(Int32 id)
{
    return await _Db.Conversations
         .Where(c => c.Participants.Any(a => a.AccountId == id))
         .Include(c => c.Participants.Select(a=> new 
                       {
                          AccountId = a.AccountId,
                          Profile = new { FullName = a.Profile.FullName,
                                          Email = a.Profile.Email
                                        }                        
                       }))
         // Only return the last message in 
         // Eventually I would not return an array with a single object but just the single object inside associated with the property LastMessageIn
         .Include(c => c.Messages.OrderBy(m => m.Date).Select(m=> new 
                       {
                          Body = m.Body,
                          SenderId = m.Sender.AccountId
                       }).Last())
         .ToListAsync();
}

此脚本返回一英里长的异常

  

{&#34; message&#34;:&#34;发生错误。&#34;,&#34; exceptionMessage&#34;:&#34; Include路径表达式必须引用导航属性在类型上定义。使用虚线路径作为参考导航属性,使用Select运算符作为集合导航属性........}

我的思想抵制理解和学习LINQ我不知道它是否仅仅是我,但是很快就要求超出基本的查询和投射它突破了我的控制

有人有一些提示吗?

3 个答案:

答案 0 :(得分:3)

我不确定我是否理解你的问题,但我相信你想要这样的事情:

public async Task<List<Conversation>> FindAllByAccountIdAsync(Int32 id)
{
    return await _Db.Conversations
         .Where(c => c.Participants.Any(p => p.AccountId == id))
         .Include(c => c.Participants)
         .Include(c => c.Messages)
         .Select(c => new 
         {
            Participants = c.Participants.Select(a=> new 
                       {
                          AccountId = a.AccountId,
                          Profile = new { FullName = a.Profile.FullName,
                                          Email = a.Profile.Email
                                        }                        
                       },
             //EDIT: using OrderByDescending and FirstOrDefault
             Messages = c.Messages.OrderByDescending(m => m.Date).Select(m=> new 
                       {
                          Body = m.Body,
                          SenderId = m.Sender.AccountId
                       }).FirstOrDefault())
             //others properties here
         }
         .ToListAsync();
}

答案 1 :(得分:1)

您无法投放包含。包含只是渴望加载。输出在C#中不会改变。只有最初加载的数据量(即性能)会发生变化。

似乎你想要一个投影而不是急切的加载,这是完全不兼容的概念。

但是我无法理解你想要达到的目的是什么。

答案 2 :(得分:1)

public async Task<List<Conversation>> FindAllByAccountIdAsync(Int32 id)
{
    return await _Db.Conversations
         .Where(c => c.Participants.Any(p => p.AccountId == id))
         .Include(c => c.Participants.Select(_=>_))
         .Include(c => c.Messages.Select(_=>_))
         .ToListAsync();
}

应该够了。