正确实现IQueryable作为模型的成员变量?

时间:2014-04-01 19:30:51

标签: c# asp.net linq entity-framework

我是.Net,ASP,实体框架和Linq的新手,所以请耐心等待......

我最初的模型设置如下:

public class Pad
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid PadId { get; set; }
    public string StreetAddress { get; set; }
    public int ZipCode { get; set; }
    public virtual ICollection<Mate> Mates { get; set; }
    public virtual ICollection<Message> Messages { get; set; }
}

(垫是聊天室 - 它包含许多Mates和数千条消息) 在Web API控制器中,我有一个功能,旨在从指定的Pad获取25条最新消息。

public IHttpActionResult GetMessages(string id)
{
    var padGuid = new Guid(id);

    // Try to find the pad referenced by the passed ID
    var pads = (from p in db.Pads
                where p.PadId == padGuid
                select p);
    if (pads.Count() <= 0)
    {
        return NotFound();
    }
    var pad = pads.First();

    // Grab the last 25 messages in this pad. 
    // PERFORMANCE PROBLEM
    var messages = pad.Messages.OrderBy(c => c.SendTime).Skip(Math.Max(0, pad.Messages.Count() - 25));
    var messagesmodel = from m in messages
            select m.toViewModel();
    return Ok(messagesmodel);
}

这个实现的问题在于,在获得计数,排序等之前,好像 EF正在将整个消息集(数千个)加载到内存中导致大量性能损失在Pads中有大量的消息。

我的第一个想法是将Pad.Messages成员类型转换为IQueryable而不是ICollection - 这应该将Linq查询推迟到SQL,或者我认为。但是,在执行此操作时,上述pad.Messages.Count()之类的函数会抱怨 - pad.Messages是空值!它会在其他地方中断,例如向Messages值添加新的Pad.Messages

这样的事情的正确实施是什么?在其他地方,我已经看到推荐的解决方案是针对上下文构建第二个查询,例如select Messages where PadId = n,但是当我可以使用Messages成员值时,这似乎不太直观。

谢谢!

2 个答案:

答案 0 :(得分:1)

var messages = db.Pads.Where(p => p.PadId == padGuid)
    .SelectMany(pad => p.Messages.OrderBy(c => c.SendTime)
        .Skip(Math.Max(0, pad.Messages.Count() - 25)));

答案 1 :(得分:-2)

如何在不实际执行数据库查询的情况下计算数据库查询中的结果数?

您打算如何在不实际执行查询的情况下获取查询中的第一项?

你也做不到;两者都必须执行查询。