0

假设我有一组Sites集合UsersUser每当我必须重新定义查询以获取给定的最后一次访问时,我发现自己违反了 DRY 原则site

例如,我的查询可能如下所示:

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 Entity 类:

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()
    }
  }
}

In this manner, whenever I am selecting a site it would be fairly trivial to grab this property. This almost works, however I am stuck trying to assign an Entity user into my UserViewModel property into the LastVisited property of my return, without an obvious way on how to project the User into my ViewModel version.

Perhaps an example would help explain. What I'm trying to accomplish would be something like this:

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    
}

NOTE = This is my point of failure. LastVisitedUser is a ViewModel with a subset of User data.

Am I going about this in the correct manner? Can I achieve what I'm trying to do, or am I horribly misguided? Am I about to sove this issue and run into others?

Thanks!

4

2 回答 2

3

Edit: The former answer was not correct. You cannot use extension method on the navigation property but you can still create extension method for the whole Site projection.

Just create simple reusable extension method:

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

Now you should be able to use that extension in your former query:

Context.Sites.Where(site => site.ID == 99).GetSiteModels();

Your example will not work because your property is not visible for Linq-to-entities.

于 2012-05-11T14:00:27.747 回答
0

If you mean that you what to reuse common queries with different extensions, you just nead to write some base query and get different results and some Where lambda expressions. If you profile it, you will see that you have just one query to DB just return IQuerable in a base query

于 2012-05-11T14:02:26.357 回答