2016-06-30 56 views
3

我已经创建了统计页面视图模型如下:的GroupBy复杂的查询

public class StatsSeasonViewModel 
{ 
    public int player_id { get; set; } 
    public string player_name { get; set; } 
    public int games_played { get; set; } 
    public int total_first { get; set; } 
    public int total_second { get; set; } 
    public int total_third { get; set; } 
    public int total_wickets { get; set; } 
    public double avg_wickets { get; set; } 
    public int total_points { get; set; } 
    public double avg_points { get; set; } 
} 

我有一个复杂的LINQ语句来填充模型。我觉得这可能是简单的,但我不知道如何做到这一点:

const int first_place = 5; 
const int second_place = 3; 
const int third_place = 1; 

var model = 
from s in _db.Stats 
join p in _db.Players 
on s.player_id equals p.player_id 
where s.season_id == current_season 
select new StatsSeasonViewModel 
{ 
    player_id = p.player_id, 
    player_name = p.name, 
    games_played = (from st1 in _db.Stats 
        where st1.player_id == s.player_id 
        select st1).Count(), 
    total_first = (from st2 in _db.Stats 
        where st2.player_id == s.player_id && st2.place == 1 
        select st2).Count(), 
    total_second = (from st3 in _db.Stats 
        where st3.player_id == s.player_id && st3.place == 2 
        select st3).Count(), 
    total_third = (from st4 in _db.Stats 
        where st4.player_id == s.player_id && st4.place == 3 
        select st4).Count(), 
    total_wickets = (from st5 in _db.Stats 
         where st5.player_id == s.player_id 
         select st5.wickets).Sum(), 
    avg_wickets = (from st5 in _db.Stats 
        where st5.player_id == s.player_id 
        select st5.wickets).Sum()/
        (from st1 in _db.Stats 
        where st1.player_id == s.player_id 
        select st1).Count(), 
    total_points = (from st5 in _db.Stats 
        where st5.player_id == s.player_id 
        select st5.wickets).Sum() + 
        (
         (from st2 in _db.Stats 
          where st2.player_id == s.player_id && st2.place == 1 
          select st2).Count() 
        ) * first_place + 
        (
         (from st3 in _db.Stats 
          where st3.player_id == s.player_id && st3.place == 2 
          select st3).Count() 
        ) * second_place + 
        (
         (from st4 in _db.Stats 
          where st4.player_id == s.player_id && st4.place == 3 
          select st4).Count() 
        ) * third_place, 
    avg_points = (
        (from st5 in _db.Stats 
         where st5.player_id == s.player_id 
         select st5.wickets).Sum() + 
        (
         (from st2 in _db.Stats 
          where st2.player_id == s.player_id && st2.place == 1 
          select st2).Count() 
        ) * first_place + 
        (
         (from st3 in _db.Stats 
          where st3.player_id == s.player_id && st3.place == 2 
          select st3).Count() 
        ) * second_place + 
        (
         (from st4 in _db.Stats 
          where st4.player_id == s.player_id && st4.place == 3 
          select st4).Count() 
        ) * third_place 
       )/
       (from st1 in _db.Stats 
        where st1.player_id == s.player_id 
        select st1).Count() 
}; 

所以我现在最大的问题是,我需要通过这个查询做一组,使其不会显示重复。但是,当我尝试添加组时,然后我迷失了如何在SELECT之后执行其余查询。我如何通过上面的查询来完成一个组,并获得我需要的结果?

编辑:FWIW这里是结果我得到:http://ecl.moyl.com/Home/Stats

第二个问题是当然的查询本身的复杂性。有没有更简单的方法来做到这一点?

+0

中的值填充其统计创建1可枚举范围 - 3然后就过滤像这样 。这里(st => range.Contains(st.place)&& st.player_id = s.player_id)那么你需要按位分组。但在数据库中将所有这些视图都放在视图中可能更合理,因此您可以从中抓取。但你得到一个Upvote为你付出的努力, –

+0

哈!感谢upvote!我想通过player_id分组,而不是放置。现在发生的事情是我得到所有球员的重复条目。我尝试将s.player_id添加到statGroup中,但是当我尝试构建模型时,select语句中所有复杂的东西都会弹出。您在数据库中创建视图可能是正确的 - 奇怪的是,我从来没有尝试过! – xgrinderx

+1

您可能会发现该视图更有用,因为如果所有内容的索引都是正确的,则不需要执行尽可能多的工作来提取该查询。您可以将该视图拖入实体框架 –

回答

4

有一对夫妇的方式把事情简单化,但回答您的主要问题:

var search = from st2 in _db.Stats 
    where st2.player_id = s.player_id 
    group st2 by st2.player_id 

你会遍历每个小组获得IGrouping<TKey, TElement>得到个别情况(ref)。

for (var playerGroup in search) 
{ 
    Console.WriteFormat("{0}: {1}\n", playerGroup.Key, playerGroup.Count()); 
} 

如果您使用稍微不同的方式编写计数/总和,那么您的代码可能会更具可读性。

例如,这个:

games_played = (from st1 in _db.Stats 
       where st1.player_id == s.player_id 
       select st1).Count(), 
total_wickets = (from st5 in _db.Stats 
        where st5.player_id == s.player_id 
        select st5.wickets).Sum() 

可能成为这样的:

var filter = st => st.player_id == s.player_id; // reuse this over and over 

games_played = _db.Stats.Where(filter).Count(), 
total_wickets = _db.Stats.Where(filter).Sum(st5 => st5.wickets) 

事实上, “有你的蛋糕和熊掌兼得”,整个过滤器变得不必要,当你使用group by语句。你必须改变你创建你的模型的方式,这样你就可以将IGrouping<int,Stat>(假设这就是类型)传递给构造函数。在这种方法的总体查询看起来是这样的:

const int first_place = 5; 
const int second_place = 3; 
const int third_place = 1; 

var model = 
    from s in _db.Stats 
    join p in _db.Players 
    on s.player_id equals p.player_id 
    where s.season_id == current_season 
    group st by st.player_id into group 
    select new StatsSeasonViewModel(group) 

现在你StatsSeasonViewModel负责基于组

public StatsSeasonViewModel(IGrouping<int,Stat> playerStats) 
{ 
    player_id = playerStats.Key; 
    games_played = playerStats.Count(); 
    total_wickets = playerStats.Sum(st=>st.wickets); 
    // .... 
} 
+0

你可以简化过滤一些统计信息,说明哪里地方<= 3 –

+0

@ johnny5,它会简化代码使其缩短,但不容易阅读,我认为Berin是在这里的位置 –

+1

Berin这很棒。这是来自经典的ASP背景,试图通过这个小应用学习c#,MVC和LINQ的总体noob。我本来就是在这个问题本身,但我想它被缓和是不必要的。我最终使用了上面johnny 5建议的View,但我认为你的回答至少指出了我正确学习如何使用分组的方向。谢谢! – xgrinderx

1

您正在使用过时的方式在MVC中编写Linq。使用的DbContext通过创建一个需要玩家ID作为变量的方法很容易地找到播放器和使用distinct返回不同的值,避免重复:

var player = _db.Players.Where(p => p.player_id == Id); 

然后由处理属性的λ-加入与玩家统计数据表格:

var st1 in _db.Stats.Where(st1 => st1.player_id == player.player_id).Distinct().Count(); 

编辑:

我改变了一点,因为你想在第二个表达不同,因为第一已经会发现一个独特的价值