我已为stats页面创建了一个viewmodel,如下所示:
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这是我得到的结果:the brilliant answer provided by Ashley Grant here
第二个问题当然是查询本身的复杂性。有更简单的方法吗?
答案 0 :(得分: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)
事实上,对于&#34;有你的蛋糕并且也吃它&#34;,当你使用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);
// ....
}
答案 1 :(得分:1)
你正在使用过时的方式在MVC中编写Linq。使用dbContext通过创建一个将播放器Id作为变量并使用Distinct返回不同值并避免重复的方法来轻松找到播放器:
var player = _db.Players.Where(p => p.player_id == Id);
然后通过lambda将玩家与stats表连接来处理属性:
var st1 in _db.Stats.Where(st1 => st1.player_id == player.player_id).Distinct().Count();
编辑:
我改变了一下,因为你会想要第二个表达式中的distinct,因为第一个已经找到了一个不同的值