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

本文关键字:变量 实现 成员 IQueryable 模型 | 更新日期: 2023-09-27 17:56:14

我是.Net,ASP,Entity Framework和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; }
}

(垫子是一个聊天室 - 它包含许多伴侣和数千条消息)在 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是一个空值!它会在其他地方中断,例如向Pad.Messages值添加新Messages

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

谢谢!

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

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)));

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

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

您不能执行任何操作;两者都必须执行查询。