2017-10-20 112 views
1

試圖讓查詢工作,但老實說不知道如何(或者甚至可能)去做,因爲我試過的所有東西都沒有奏效。LINQ GroupBy與AutoMapper的聚合

總共查詢6個表格:Person,PersonVote,PersonCategory,Category,City和FirstAdminDivision。

PersonVote是一個人的用戶評論表,它包含一個名爲Vote的列,它是一個接受1-5(5爲「最佳」)值的小數。 FirstAdminDivision將與美國各州同義,如加利福尼亞州。 Person表有一個名爲CityId的列,它是City的外鍵。我相信其他表格大多是不言自明的,所以我不會評論,除非需要。

我的目標是創建一個查詢,返回一個「最受歡迎」人物的列表,該列表將基於PersonVote表上的特定人物的所有投票的平均值。例如,如果一個人有3張選票,3張選票都是「5」,那麼他們將成爲名單中的第一位......在這一點上,他並不真正在乎二級排序......例如......像大多數選票一樣一條領帶會「贏」。

我在沒有AutoMapper的情況下工作,但我喜歡AM使用ProjectTo擴展方法進行投影的能力,因爲代碼非常乾淨可讀,如果可能,寧願使用該方法,但一直沒有得到它的運氣上班。

這就是我所做的工作....所以基本上,我想看看是否可以用ProjectTo而不是LINQ的Select方法。

List<PersonModel> people = db.People 
        .GroupBy(x => x.PersonId) 
        .Select(x => new PersonModel 
        { 
         PersonId = x.FirstOrDefault().PersonId, 
         Name = x.FirstOrDefault().Name, 
         LocationDisplay = x.FirstOrDefault().City.Name + ", " + x.FirstOrDefault().City.FirstAdminDivision.Name, 
         AverageVote = x.FirstOrDefault().PersonVotes.Average(y => y.Vote), 
         Categories = x.FirstOrDefault().PersonCategories.Select(y => new CategoryModel 
         { 
          CategoryId = y.CategoryId, 
          Name = y.Category.Name 
         }).ToList() 
        }) 
        .OrderByDescending(x => x.AverageVote) 
        .ToList(); 
+0

你試過https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions? – abatishchev

+0

是的,我已閱讀文檔,並嘗試了幾種不同的方法,但尚未拿出任何實際可行的方法。我要麼結束了這個例外:「缺少從IGrouping'2到PersonModel的映射。使用Mapper.CreateMap 」或這一個創建:「LINQ to Entities不支持指定的類型成員'AverageVote' 」。我明白這兩者是什麼,但我不知道如何構建查詢來完成我所追求的內容,或者如果我想要甚至可以使用AM的Projection。 – user1011627

+0

您是否可以僅使用沒有AM的EF構造並執行所需的查詢? – abatishchev

回答

3

通過查看您的代碼示例,我試圖確定您的模型將用於設置示例。

 Mapper.Initialize(cfg => 
     { 
      cfg.CreateMap<IEnumerable<People>, PersonModel>() 
       .ForMember(
        model => model.LocationDisplay, 
        conf => conf.MapFrom(p => p.FirstOrDefault().City.Name)) 
       .ForMember(
        model => model.AverageVote, 
        conf => conf.MapFrom(p => p.FirstOrDefault().PersonVoes.Average(votes => votes.Vote))); 
     }); 

所以給出的下列對象:

public class People 
{ 
    public int PeronId { get; set; } 
    public string Name { get; set; } 
    public City City { get; set; } 
    public IList<PersonVotes> PersonVoes { get; set; } 
} 

public class PersonVotes 
{ 
    public int Vote { get; set; } 
} 

public class City 
{ 
    public string Name { get; set; } 
} 

public class FirstAdminDivision 
{ 
    public string Name { get; set; } 
} 

public class PersonModel 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
    public string LocationDisplay { get; set; } 
    public double AverageVote { get; set; } 
} 

要通過靜態API使用ProjectTo擴展,然後我初始化AM:我只用了幾個屬性的顯示功能實現

var people = new List<People>() 
     { 
      new People 
      { 
       PeronId = 1, 
       City = new City 
       { 
        Name = "XXXX" 
       }, 
       PersonVoes = new List<PersonVotes> 
       { 
        new PersonVotes 
        { 
         Vote = 4 
        }, 
        new PersonVotes 
        { 
         Vote = 3 
        } 
       } 

      } 
     }; 

我會再有查詢:

var result = people 
      .GroupBy(p => p.PeronId) 
      .Select(peoples => peoples) 
      .AsQueryable() 
      .ProjectTo<PersonModel>(); 

我只是在內存對象中使用,所以這就是爲什麼我轉換爲IQueryable使用AM中的ProjectTo擴展方法。

我希望這是你要找的。歡呼聲中,

更新的LINQ to Entities查詢:

var result = db.People 
    .GroupBy(p => p.PersonId) 
    .ProjectTo<PersonModel>(base.ConfigProvider) // AM requires me to pass Mapping Provider here. 
    .OrderByDescending(x => x.AverageVote) 
    .ToList(); 
+0

謝謝ODawg ......這讓我走上了正軌。我更新了您的答案,以包含我需要的實際LINQ語句的LINQ To Entities版本。對我來說關鍵在於你發佈的AM映射。 – user1011627