Skip to main content
4 of 4
suggested a simpler model
Mathieu Guindon
  • 75.1k
  • 18
  • 191
  • 463

Don't use underscores in identifiers. If that's how the database has them, use a ColumnAttribute to specify the column name scratch that, you're going code-first. This:

public int Tournament_Id { get; set; }

public int Match_Id { get; set; }
public int Team_Id { get; set; }

public int PlayerAccount_Id { get; set; }

Is much more seesharpesque like this:

public int TournamentId { get; set; }

public int MatchId { get; set; }
public int TeamId { get; set; }

public int PlayerAccountId { get; set; }

I like that most of these foreign key properties follow a very predictable naming pattern [ForeignEntityTypeName]Id - IIRC that's all EF needs to be able to infer the foreign keys.

...With the exception of TournamentMatchResult, which breaks the pattern with its MatchId (/Match_Id) property:

public int Match_Id { get; set; }
public virtual TournamentMatch TournamentMatch { get; set; }

Would be more consistent like this:

public int TournamentMatchId { get; set; }
public virtual TournamentMatch TournamentMatch { get; set; }

You're using System.ComponentModel.DataAnnotations;; it works, but I find all these attributes pollute the POCO:

[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; }

EF is smart enough to know Id is your [Key] (by naming convention), and smart enough to know Team is a FK that uses TeamId (by naming convention) - I'm not sure whether Team_Id breaks it or not, but relying on EF's established conventions makes your POCO code less polluted:

public int Id { get; set; }

[Required]
public int TournamentMatchId { get; set; }

[Required]
public int TeamId { get; set; }

[Required]
public double Score { get; set; }

public virtual TournamentMatch TournamentMatch { get; set; }
public virtual Team Team { get; set; }

Now all that's left is [Required] attributes. You could remove them too, if you moved POCO configurations/mappings elsewhere.


One way of doing that would be in the OnModelCreating override of your DbContext:

modelBuilder.Entity<TournamentMatchResult>()
            .Property(t => t.TournamentMatchId).IsRequired();
modelBuilder.Entity<TournamentMatchResult>()
            .Property(t => t.TeamId).IsRequired();
modelBuilder.Entity<TournamentMatchResult>()
            .Property(t => t.Score).IsRequired();

Obviously this gets very verbose, very fast. An alternative is to use EntityMappingConfiguration<TEntityType> classes. For each entity type, you create a mapping class:

public class TournamentMatchResultMap : EntityMappingConfiguration<TournamentMatchResult>
{
    public TournamentMatchResultMap()
    {
        Property(t => t.TournamentMatchId).IsRequired();
        Property(t => t.TeamId).IsRequired();
        Property(t => t.Score).IsRequired();
    }
}

You can also use these mapping classes to configure mapped column names and table, and relationships with other entities. See EntityMappingConfiguration<TEntityType>

Then the OnModelCreating override simply loads all the configurations:

modelBuilder.Configurations.Add(new TournamentMatchResultMap());

I find that's the cleanest approach; it lets your POCO classes be POCO's, it leaves the OnModelCreating method free of verbose fluent API mappings, and it puts each entity's configurations into its own class.


Let's look at the relationships. If I didn't make mistakes, this is what your code can be modeled as:

http://yuml.me/edit/5090cace

As @Jeroen explains, EF doesn't need junction tables to model a many-to-many relationship; PlayerTeamKey and TeamTournamentKey entities can be removed.

I would believe this simplified model could very well suit your needs:

http://yuml.me/edit/15eb9eca

The idea is to use the navigation properties to navigate between entities - from a business standpoint it makes sense for tournament matches to know what teams are involved, but from a data standpoint, it doesn't: when your application creates a new tournament, it also creates a TournamentMatchResult for all teams involved, with each team's score at 0 - and that's enough for a TournamentMatch to know what teams are playing.

As the game evolves, you can then update the TournamentMatchResult records, and if a TournamentMatch needs to know what teams are involved, it can easily find out by selecting its .TournamentMatchResults.Select(result => result.Team).

Notice this results in simple, easy-to-follow, one-to-many relationships everywhere.

Mathieu Guindon
  • 75.1k
  • 18
  • 191
  • 463