我是.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成员值时,这似乎不太直观。
谢谢!
答案 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)
如何在不实际执行数据库查询的情况下计算数据库查询中的结果数?
您打算如何在不实际执行查询的情况下获取查询中的第一项?
你也做不到;两者都必须执行查询。