【问题标题】:LINQ grouping and ordering of top 5 rows into ViewModel List将前 5 行的 LINQ 分组和排序到 ViewModel 列表中
【发布时间】:2015-02-15 01:52:07
【问题描述】:

我正在尝试为我的垒球 Web 应用程序创建一个新的前五名热门排行榜。我是 MVC 的新手,我无法将此查询放在一起并将信息传递给我的 ViewModel。如果可能的话,我想在控制器中使用像“var results”这样的非查询调用。我正在尝试按 Stat 表中的 PlayerID 对 AtBats 进行分组。对于这个列表,我还希望能够从我的视图中的 Player 表中调用玩家的 FirstName 和 LastName。感谢您的帮助!

在 Stat.cs 中

using System;

namespace TheFlyingPig.Models
{
    public class Stat
    {
        public int StatID { get; set; }
        public int SeasonID { get; set; }
        public int PlayerID { get; set; }
        public DateTime GameDate { get; set; }
        public int AtBats { get; set; }
        public int Hits { get; set; }
        public int Walks { get; set; }
        public int Singles { get; set; }
        public int Doubles { get; set; }
        public int Triples { get; set; }
        public int HomeRuns { get; set; }
        public int RBIs { get; set; }
        public int Runs { get; set; }
        public int ReachedOnErrors { get; set; }
        public int SacrificeFlies { get; set; }

        public virtual Season Season { get; set; }
        public virtual Player Player { get; set; }
    }
}

在 Player.cs 中

using System;
using System.Collections.Generic;

namespace TheFlyingPig.Models
{
    public class Player
    { 
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public virtual ICollection<Stat> Stats { get; set; }
    }
}

在 Season.cs 中

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace TheFlyingPig.Models
{
    public class Season
    {
        public int SeasonID { get; set; }
        public string SeasonName { get; set; }

        public virtual ICollection<Stat> Stats { get; set; }
    }
}

在 TeamStat.cs(我试图将这些数据推送到我的 ViewModel)中

//Get the season leaders from controller
public List<Stat> SeasonLeadersHits { get; set; }

我已经在我的控制器 (HomeController.cs) 中尝试了以下两个选项,但我似乎无法在此取得任何进展来获得团队的 Top 5 Hits 领导者。

var lastSeasonId = db.Seasons.OrderByDescending(u => u.SeasonID).Select(u => u.SeasonID).FirstOrDefault();

var leadersAtBats = (from s in db.Stats
                     join p in db.Players on s.PlayerID equals p.ID
                     where s.SeasonID == lastSeasonId
                     group s.Hits by s.PlayerID into g
                     order by s.Hits descending
                     select new { LeaderID = g.Key, LeaderList = g.ToList() })
                     .Take(5);

var results = db.Stats.Where(s => s.SeasonID == lastSeasonId).GroupBy(s => s.PlayerID, s => s.Hits, (key, g) => new { PlayerId = key, Hits = g.ToList() });

var view = new TeamStat() { SeasonLeadersHits = results };
return View(view);

【问题讨论】:

  • 错误表示它无法将类型“System.Linq.IQueryable”隐式转换为“System.Collections.Generic.List”。存在显式转换(您是否缺少演员表?)
  • 您的属性是List&lt;Stat&gt; SeasonLeadersHits,但您的所有查询都在创建匿名类型(select 语句),而不是 typeof Stat
  • 斯蒂芬,我在网上看到过这个解释,但我不明白如何解决它。我怎样才能将它添加到我的 TeamStat ViewModel 中?

标签: c# sql linq visual-studio-2013 asp.net-mvc-5


【解决方案1】:

'GroupBy' 的原因是什么?在我看来,您需要做的就是从 db.Stats 中按 Hits 降序选择前 5 行。像这样:

var results = (
    from s in db.Stats
    join p in db.Players on s.PlayerID equals p.ID
    where s.SeasonID == lastSeasonId
    order by s.Hits descending
    select new { Player = p, Stats = s })
    .Take(5).ToList();

** 我假设Stats 中的每一行代表一年。

编辑:

好的,所以每个 Stat 对象代表一个游戏(第一次错过了)。如果您希望 Stats 按年份总计,那么查询中缺少的部分是点击的 Sum()(可能还有其他统计信息)。此查询将为您提供按总点击数排名的前 5 个赛季,以及与之关联的赛季和球员。

var hitLeaders = (from s in stats
                  join p in players on s.PlayerID equals p.ID
                  group s by new { s.PlayerID, s.SeasonID } into g
                  select new 
                  { 
                     PlayerID = g.Key.PlayerID, 
                     SeasonID = g.Key.SeasonID, 
                     Hits = g.Sum(sum => sum.Hits),
                     AtBats = g.Sum(sum => sum.AtBats),
                     Walks = g.Sum(sum => sum.Walks),
                     Singles = g.Sum(sum => sum.Singles),
                     Doubles = g.Sum(sum => sum.Doubles),
                     Triples = g.Sum(sum => sum.Triples),
                     HomeRuns = g.Sum(sum => sum.HomeRuns),
                     RBIs = g.Sum(sum => sum.RBIs),
                     Runs = g.Sum(sum => sum.Runs),
                     ReachedOnErrors = g.Sum(sum => sum.ReachedOnErrors),
                     SacrificeFlies = g.Sum(sum => sum.SacrificeFlies)
                  }).OrderByDescending(s => s.Hits).Take(5);

现在,您将遇到的第二个问题是您无法将此查询的结果分配给您的视图模型,因为它会生成一个IEnumerable&lt;of AnonymousType&gt;,但视图模型需要一个List&lt;Stat&gt;。我的建议是创建一个代表玩家一年内总统计数据的对象;像这样:

public class TotalStat
{
    public int TotalStatID { get; set; }
    public int SeasonID { get; set; }
    public int PlayerID { get; set; }
    public int AtBats { get; set; }
    public int Hits { get; set; }
    public int Walks { get; set; }
    public int Singles { get; set; }
    public int Doubles { get; set; }
    public int Triples { get; set; }
    public int HomeRuns { get; set; }
    public int RBIs { get; set; }
    public int Runs { get; set; }
    public int ReachedOnErrors { get; set; }
    public int SacrificeFlies { get; set; }
}

然后,您只需将视图模型更改为:

public List<TotalStat> SeasonLeadersHits { get; set; }

并更改查询以创建IEnumerable&lt;TotalStat&gt;。您可以通过将new {} 更改为new TotalStat {} 来实现,如下所示:

//...
group s by new { s.PlayerID, s.SeasonID } into g
select new TotalStat
{ 
    PlayerID = g.Key.PlayerID, 
//...

【讨论】:

  • 我需要 GroupBy,因为每个球员在赛季中都可以有多个 StatID。我需要每个球员 ID 的赛季总数,然后按点击次数降序排列。
  • 像魅力一样工作,但我不得不更改公共列表 SeasonLeadersHits { get;设置;} 公开 IEnumerable SeasonLeadersHits {get;放; } 让它工作。非常感谢!
猜你喜欢
  • 2022-01-04
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 2013-06-21
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多