2017-10-20 113 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