假设我有一个模型足球Team。与其他团队一起在小组中扮演Matches。现在,我想从列表中选择排名前2的球队。比分照常计算:胜利3分,平局1分,失败0分。

Match的模型如下所示:

[Key]
public int MatchId{get;set;}
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
[ForeignKey("HomeTeamId")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("AwayTeamId")]
public virtual Team AwayTeam { get; set; }
public int? HomeTeamScored { get; set; }
public int? AwayTeamScored { get; set; }


我已经测试了这5个解决方案:

1)有一个视图而不是从表中获取分数列的表格,但是这使编程部分变得复杂,因为我不得不以某种方式告诉EF使用该表进行插入,但是该视图用于显示数据

2)将Score列设为未映射,然后参加所有团队,计算得分,如下所示:

var list = db.Teams.ToList();

foreach(var team in list)
{
    team.Score = db.Matches.Where(...).Sum();
}


然后只需按Score排序列表,然后先获取2。

3)另一种方法是

var list = db.Teams.OrderByDesc(t => db.Matches.Where(...).Sum()).Take(2).ToList();


我将不得不做很多检查是否为空,还要检查哪个球队获胜或被平局,我所寻找的球队是在主场还是客场出战,等等。

4)
另一种选择是每次我添加/编辑比赛时为球队重新计算Score,但是我觉得这是一种非常不专业的方法。

就像我说的那样,这些方法中的每一个都是可以引导我完成任务的解决方案,但是...我有第六种感觉,就是我似乎不怎么努力就可以做到这一点。任何人都可以建议我所缺少的吗?

附言如果它影响了答案,我们假设我使用的是最新版本。

最佳答案

当数据冗余迫在眉睫时,通常是标准化的解决方案。我认为在您的情况下,您既需要标准化又需要冗余。

Match中的重复属性“很臭”。他们似乎要求规范化。仔细观察就会发现,并非所有人都如此。一场比赛总是由两队组成。因此,两个TeamId都可以(以及随附的参考文献)。但是您可以以不同的方式存储分数。

看一下这个可能的模型:

class Team
{
    public int TeamId { get; set; }
    // ...
    public ICollection<MatchTeam> MatchTeams { get; set; }
}

class Match
{
    public int MatchId { get; set; }
    public int HomeTeamId { get; set; }
    public int AwayTeamId { get; set; }
    public virtual Team HomeTeam { get; set; }
    public virtual Team AwayTeam { get; set; }
}

class MatchTeam
{
    public int MatchId { get; set; }
    public int TeamId { get; set; }
    public int Scored { get; set; } // Number of goals/points whatever
    public int RankingScore { get; set; } // 0, 1, or 3
}


MatchTeam是在1场比赛中存储1支球队的成就的实体。 Scored属性是HomeTeamScoredAwayTeamScored的归一化结果。优点是:该属性不可为空:当结果为事实时,将创建一个MatchTeam条目。

冗余位于RankingScore属性中。这必须在输入或修改比赛时确定,并且取决于分数(并应与分数保持一致)。与冗余一样,存在数据不一致的危险。但这有很大的危险吗?如果只有一种维修方法可以输入或修改MatchTeam数据,则危险将被充分限制。

优点是,现在可以在运行时收集每个团队的总成绩了:

var topTeams = context.Teams
              .OrderByDescending(t => t.MatchTeams.Sum(mt => mt.RankingScore))
              .Take(2);

10-02 01:46
查看更多