我将User
对象存储在RavenDB中。每个User
都具有一个User.Id
属性。
我还有一个Relationship
类,它将两个User.Id
链接在一起,以创建导师/学员关系,如下所示:
public class User
{
public string Id { get; set; }
public string UserName { get; set; }
... more properties
}
public class Relationship
{
public string Id { get; set; }
public string MentorId { get; set; }
public string MenteeId { get; set; }
public RelationshipStatus Status { get; set; }
}
现在,我想检索给定导师的心理医生列表。我通过以下方式做到了这一点:
public static List<User> GetMentees(IDocumentSession db, string mentorId)
{
var mentees = new List<User>();
db.Query<Relationship>()
.Where(r => r.MentorId == mentorId)
.Select(r => r.MenteeId)
.ForEach(id => mentees.Add(db.Load<User>(id)));
return mentees;
}
这似乎很好,但我肩上的编码天使对嵌套使用IDocumentSession
(db)和需要多个Load
调用来填充Mentees
列表所产生的气味嗤之以鼻。
如何使用最佳实践RavenDB语法优化此方法?
编辑感谢@Jonah Himango(见下面接受的答案),他为我解决了多次调用数据库的问题。此外,我还创建了一个名为"Memoize"的新扩展方法,以消除对外部"mentees"结果列表的需要(见上面的代码)。
这是经过优化的代码。请随时发表评论并进一步完善。
Linq
public static List<User> GetMentees(IDocumentSession db, string mentorId)
{
return db.Query<Relationship>()
.Customize(x => x.Include<Relationship>(o => o.MenteeId))
.Where(r => r.MentorId == mentorId)
.Memoize()
.Select(r => db.Load<User>(r.MenteeId))
.ToList();
}
扩展方法
public static List<T> Memoize<T>(this IQueryable<T> target)
{
return target.ToList();
}
注意:这个扩展方法可能看起来完全多余(事实确实如此),但它激怒了我的极客,因为我必须调用一个名为ToList()
的函数,不是为了创建列表,而是为了强制执行Linq语句。因此,我的扩展方法只是将ToList()
重命名为更准确的Memoize()
。
您将需要使用。包括查询自定义,以告诉Raven将每个关系的相关用户对象包括在内:
db.Query<Relationship>()
.Customize(x => x.Include<Relationship>(o => o.MenteeId))
.Where(r => r.MentorId == mentorId)
.Select(r => r.MenteeId)
.ForEach(id => mentees.Add(db.Load<User>(id))); // .Load no longer makes a call to the DB; it's already loaded into the session!
此处的相关文档:
对Load()的调用完全由客户端解决(即没有对RavenDB服务器的额外请求),因为[相关]已通过检索到对象。包括呼叫。