假设我有一组Sites
,其集合为Users
。每当我必须重新定义查询以获取给定User
的上次访问site
时,我发现自己违反了DRY主体。
例如,我的查询可能如下所示:
from site in Context.Sites
where site.ID == 99
select new {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.Users.OrderByDescending(u => u.LastVisited).Select(u => new {
ID = u.ID,
Username = u.Username,
Email = u.EmailAddress
})
.FirstOrDefault()
}
该查询返回我想要的内容,但我发现自己在多个地方为LastVisitedUser重复这个相同的选择,因为我以不同的方式选择网站来填充我的各种ViewModel。
所以,我认为我只是使用如下属性扩展我的Site Entitiy类:
public partial class Site {
public LastVisitedUser {
get {
var query = from user in Users
where user.SiteID == this.ID
orderby user.LastVisited descending
select user;
return query.FirstOrDefault()
}
}
}
通过这种方式,每当我选择一个网站时,抓住这个属性都是相当简单的。这个几乎有效,但是我试图将我的UserViewModel属性中的Entity用户分配到我的返回的LastVisited属性,而没有明显的方法来如何将User
投影到我的ViewModel中版本
也许一个例子可以帮助解释。我想要完成的事情是这样的:
from site in Context.Sites
where site.ID == 99
select new SiteViewModel {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.LastVisitedUser <--- NOTE
}
注意=这是我的失败点。 LastVisitedUser
是一个ViewModel,其中包含User
个数据的子集。
我是否以正确的方式解决这个问题?我可以实现我想要做的事情,还是我可怕的被误导?我是否想要解决这个问题并遇到其他问题?
谢谢!
答案 0 :(得分:3)
编辑:前一个答案不正确。您不能在导航属性上使用扩展方法,但仍可以为整个Site
投影创建扩展方法。
只需创建简单的可重用扩展方法:
public static IQueryalbe<SiteModel> GetSiteModels(this IQueryable<Site> query)
{
return query.Select(site => new SiteModel {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.Users
.OrderByDescending(u => u.LastVisited)
.Select(u => new LastVisitedUser {
ID = u.ID,
Username = u.Username,
Email = u.EmailAddress
}});
}
现在,您应该能够在之前的查询中使用该扩展程序:
Context.Sites.Where(site => site.ID == 99).GetSiteModels();
您的示例无效,因为您的属性对于Linq-to-entities不可见。
答案 1 :(得分:0)
如果您的意思是重复使用具有不同扩展名的常见查询,那么您只需要编写一些基本查询并获得不同的结果和一些Where lambda表达式。如果您对其进行分析,您将看到只有一个查询到DB只是在基本查询中返回IQuerable