LINQ GroupBy 与 AutoMapper 的聚合

use*_*627 5 c# linq 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();
Run Code Online (Sandbox Code Playgroud)

The*_*ock 5

By looking at your code sample I tried to determine what your models would be in order to setup an example. I only implemented using a few of the properties to show the functionality:

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; }
}
Run Code Online (Sandbox Code Playgroud)

To use the ProjectTo extension I then initialize AM through the static API:

        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)));
        });
Run Code Online (Sandbox Code Playgroud)

So given the following object:

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

            }
        };
Run Code Online (Sandbox Code Playgroud)

I would then a have query:

var result = people
            .GroupBy(p => p.PeronId)
            .Select(peoples => peoples)
            .AsQueryable()
            .ProjectTo<PersonModel>();
Run Code Online (Sandbox Code Playgroud)

I'm just using in memory objects so that is why I convert to IQueryable to use the ProjectTo extension method in AM.

I'm hoping this was what you're looking for. Cheers,

UPDATED FOR LINQ TO ENTITIES QUERY:

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();
Run Code Online (Sandbox Code Playgroud)