我正在设计一个新的应用程序来跟踪体育统计代码优先迁移。我有最起码的POCO设置。问题是,我不满意的设计,特别是球员,球队和比赛是如何相互关联。
我很感谢大家的意见和建议。
/// <summary>
/// Player account is a separate entity from the actual user account.
/// Player account allows a user to join teams and participate in a tournament.
/// </summary>
public class PlayerAccount
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
/// <summary>
/// TournamentPlayerKeys tells us which team this player is competing with
/// in a certain tournament.
/// </summary>
public virtual ICollection<PlayerTeamKey> PlayerTeamKeys { get; set; }
public virtual ICollection<PlayerMatchStat> PlayerMatchStats { get; set; }
}using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// Team can be formed by a single user or a group of user. You'll need a team to join a tournament.
/// A single user can form his own team.
/// </summary>
public class Team
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<PlayerTeamKey> PlayerTeamKeys { get; set; }
public virtual ICollection<TeamTournamentKey> TeamTournamentKeys { get; set; }
}using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// Tournaments are basically a collection of games in one event.
/// For example, Summer 2014 Basketball League.
/// </summary>
public class Tournament
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<TeamTournamentKey> TeamTournamentKeys { get; set; }
public virtual ICollection<TournamentMatch> TournamentMatches { get; set; }
}在一次比赛中,有多个比赛实例(游戏):
/// <summary>
/// Match represents one occurence of a game in a league.
/// </summary>
public class TournamentMatch
{
[Key]
public int Id { get; set; }
[Required]
public int Tournament_Id { get; set; }
[ForeignKey("Tournament_Id")]
public virtual Tournament Tournament { get; set; }
public virtual ICollection<TournamentMatchResult> TournamentMatchResults { get; set; }
}当然,在一场比赛中,我们有多个匹配结果的实例。Score属性决定谁是赢家。
/// <summary>
/// This is the result of a league match.
/// </summary>
public class TournamentMatchResult
{
[Key]
public int Id { get; set; }
[Required]
public int Match_Id { get; set; }
[Required]
public int Team_Id { get; set; }
[Required]
public double Score { get; set; }
[ForeignKey("Match_Id")]
public virtual TournamentMatch TournamentMatch { get; set; }
[ForeignKey("Team_Id")]
public virtual Team Team { get; set; }
public virtual ICollection<PlayerMatchStat> PlayerMatchStat { get; set; }
}我有一个多部分的键来创建球员和团队之间的关系:
/// <summary>
/// This is a multipart key class that defines a player as part of a team.
/// Mind the naming convension, from smaller entity to a bigger entity; Player > Team.
/// </summary>
public class PlayerTeamKey
{
[Required]
public int PlayerAccount_Id { get; set; }
[Required]
public int Team_Id { get; set; }
[ForeignKey("PlayerAccount_Id")]
public virtual PlayerAccount Player { get; set; }
[ForeignKey("Team_Id")]
public virtual Team Team { get; set; }
}我在球队和锦标赛上也有这样的表现:
/// <summary>
/// This is a multipart key class that is a combination of a team id and a tournament id.
/// This basically tells us that the team with the given id is going to participating on a tournament with the given id.
/// </summary>
public class TeamTournamentKey
{
[Required]
public int Team_Id { get; set; }
[Required]
public int Tournament_Id { get; set; }
[ForeignKey("Team_Id")]
public virtual Team Team { get; set; }
[ForeignKey("Tournament_Id")]
public virtual Tournament Tournament { get; set; }
}发布于 2014-07-12 18:16:50
我举了一个小小的例子告诉你,你所有的忧虑都过去了。不过,在您自己实现这一点之前,请记住Mat的备注:我将其作为一个快速草图,并将映射与上下文分离,命名约定等对于代码的清晰性非常重要。
尽管如此,这个小设置向您展示了如何更改它:
public class Player
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public virtual ICollection<Team> Teams { get; set; }
}
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Player> Players { get; set; }
}就这样。你完蛋了!我们现在需要做的就是配置我们的映射,这样它就会生成中间表本身:
public class TournamentContext : DbContext
{
public DbSet<Player> Players { get; set; }
public DbSet<Team> Teams { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Player>()
.HasKey(x => x.Id)
.HasMany(x => x.Teams);
modelBuilder.Entity<Team>()
.HasKey(x => x.Id)
.HasMany(x => x.Players);
}
}如果您想自己测试它,可以使用以下示例代码:
static void Main(string[] args)
{
using (var context = new TournamentContext())
{
context.Database.ExecuteSqlCommand("delete from Players");
context.Database.ExecuteSqlCommand("delete from Teams");
var team1 = context.Teams.Add(new Team {Name = "Power rangers"});
var team2 = context.Teams.Add(new Team { Name = "Ninja turtles" });
context.Players.Add(new Player
{
Firstname = "John",
Lastname = "Johnson",
Teams = new List<Team> {team1, team2}
});
context.Players.Add(new Player
{
Firstname = "Jack",
Lastname = "Jackson",
Teams = new List<Team>{team1}
});
context.SaveChanges();
foreach (var player in context.Players.ToList())
{
Console.WriteLine("Player: " + player.Id);
Console.WriteLine("Teams: " + string.Join(", ", player.Teams.Select(x => x.Name).ToArray()));
}
}
Console.Read();
}通过服务器资源管理器查看我们的数据库,我们现在可以看到以下表:



有了这个输出:

您会发现您可以大量地配置它,并在生成的表中添加限制,但是我太懒了,无法自己查找它们;映射不是我最好的一面。这应该给您一个关于如何摆脱那些不那么漂亮的中间表的想法。
发布于 2014-07-12 18:31:36
我建议对主键和外键使用相同的名称,遵循一些一致的模式:
它可以是_id或Id,因此在PlayerAccount表中有主键PlayerAccountId (而不仅仅是Id),在PlayerTeamKey中也有作为外键的PlayerAccountId。
在非小项目中,字段和类的命名非常重要。
我相信,不管您遵循的是代码优先还是模型优先,还是其他方法,您的问题都是推动类的设计和命名。我个人非常喜欢使用PowerToys的第二个模式--您可以在像Enterprise 2这样的对象设计工具(如Enterprise 2)中使用Server这样的对象设计工具来完成数据图1。然后将此设计导出为代码--首先使用PowerToys。
您必须组织使用的术语,并将它们转换为有意义的类设计,这并不容易。
下面是您提供的类的图表:

您可以很容易地在Visual中创建这个类图。显然有缺少比赛类。(Match_Id -外键)(好的,它没有丢失,这是一个链接到非常可疑的TournamentMatch类,我明白)
您的基本类是Player (最初的PlayerAccount)、Team、Match (最初的TournamentMatchResult)、锦标赛。我把课程改名了--这样就更容易理解了。其他类是用于创建M:N关系的空关联类。这些M:N关系真的有必要吗?
没有答案的问题太多了

基本上,您的主要问题是在您的设计中有太多的无属性关联类(PlayerTeamKey、TournamentMatch .我看到了其中的4个),这很可能是类设计中的错误。
您应该首先回答我在第二张图表中所写的问题,然后才开始编写您的代码。否则你的设计就会失败。
为了举例说明如何通过回答分析性问题来进行适当的设计,我创建了简化版本。正如我所相信的,根据你回答分析性问题的方式,你可以用4个类来创建你的模型。这个模型可以很容易地首先转换为C#代码,但是第一次确认这是否是您所要寻找的模型。

还有一个提示:如果你在比赛中使用单词匹配,不要把它叫做游戏,尽量少用一些绝对必要的术语。
https://codereview.stackexchange.com/questions/43762
复制相似问题