2011-10-20 95 views
1

想象下列情况:LINQ与多个群组加入

每个玩家(实体)都可以参与任意数量的攻击(实体)。攻击可能会导致杀戮(实体)。 Attack.Player映射到参与攻击的玩家。杀死。攻击导致杀死的攻击地图。因此,Kill.Attack.Player会将杀戮映射到玩家。

我想产生如下报告: 玩家A发动了10次攻击,造成7人死亡。玩家B造成8次攻击,造成4人死亡。玩家C进行0次攻击,造成0次杀戮。

我怎样才能使用LINQ?我以为我能做到:

from player in Players 
join attack in Attacks on player equals attack.Player into attacksByPlayer 
join kill in Kills on attack equals kill.Attack into killsByPlayer 
select new { Player = player, Attacks = attacksByPlayer.Count(), Kills = killsByPlayer.Count() } 

显然,这是不正确的各种原因(和不会建立)。

另外,我将如何创建相同的报告,但使用内部连接,因为他没有攻击而不报告播放器C?

非常感谢您的帮助!

+0

是否可以从播放器遍历攻击,然后从每个附加到杀死? – Ankur

+0

嗨,Ankur。感谢您的及时回复。不,他们通过外键链接。所以,你有Attack.Player和Kill.Attack,但是你无法绕过它。 Wouter,谢谢, – Pato

回答

1

以下查询应该做的伎俩。它只会显示进行攻击的玩家并计算攻击并杀死你。

using (Model m = new Model()) 
{ 
    var result = from attack in m.Attacks 
       group attack by attack.Player into attacksForPlayer 
       select new 
       { 
        PlayerName = attacksForPlayer.Key.Name, 
        NumberOfAttacks = attacksForPlayer.Count(), 
        NumberOfKills = (from k in m.Kills 
             where attacksForPlayer.Contains(k.Attack) 
             select k).Count() 
       }; 

    // The result can be read like this: 
    foreach (var r in result) 
    { 
     // r.PlayerName, r.NumberOfAttacks, r.NumberOfKills 
    } 
} 
+0

谢谢。这样可行。也有很多可能的选择。我试图找到最干净,最简洁的解决方案,并且允许将任意数量的表“加入”并将它们的列进行聚合 - 而无需进行额外的嵌套查询。我在下面发布的解决方案也是一个很好的解决方案。 – Pato

1
from player in players 
from attack in attacks.Where(attack => attack.Player == player).DefaultIfEmpty() 
from kill in kills.Where(kill => kill.Attack == attack).DefaultIfEmpty() 
group new { attack, kill } by player into g 
select new { 
    Player = player, 
    Attacks = g.Count(x => x.attack != null), 
    Kills = g.Count(x => x.kill != null) 
}