Search code examples
c#entity-frameworkef-code-first

Entity Framework - list of items is not loading


I'm trying to save games in database with EntityFramework Code-First.

There are fragments of my classes:

/// <summary>
/// Game class
/// </summary>
public class Game : ObservableObject
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int GameId { get; set; }

    /// <summary>
    /// List of teams
    /// <see cref="Models.Teams"/>
    /// </summary>
    public Teams Teams
    {
        get
        {
            return teams;
        }
        set
        {
            teams = value;
            OnPropertyChanged("Teams");
        }
    }
}


/// <summary>
/// Teams class
/// </summary>
public class Teams : ObservableObject, IEnumerable<Team>
{
    public int GameId { get; set; }

    public Game Game { get; set;}

    List<Team> teamsList = new List<Team>();

    /// <summary>
    /// List of teams
    /// </summary>
    public List<Team> TeamsList
    {
        get
        {
            return teamsList;
        }
        set
        {
            teamsList = value;
            OnPropertyChanged("TeamsList");
        }
    }
}

/// <summary>
/// Team (group of players)
/// </summary>
public class Team : ObservableObject
{


    #region Properties & fields

    List<Player> players = null;
    static int NumberOfTeams = 0;

    /// <summary>
    /// List of players in team
    /// </summary>
    public List<Player> Players
    {
        get
        {
            return players;
        }
        set
        {
            players = value;

            OnPropertyChanged("NumberOfPlayers");
            OnPropertyChanged("IsEmpty");
            OnPropertyChanged("IsNotDefault");
            OnPropertyChanged("Players");
        }
    }
}

/// <summary>
///Defines player
/// </summary>
public class Player : Models.Person
{

    /// <summary>
    /// Identifies player in game. Also lets to recover player's statistics from last month
    /// </summary>
    public int PlayerId { get; set; }
}

And the Entity Framework part:

 public class GameContext : DbContext
{
    public GameContext() : base("Db")
    {
        this.Configuration.LazyLoadingEnabled = false;
        this.Configuration.ProxyCreationEnabled = true;
    }

    public DbSet<Models.Game> Games { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure domain classes using modelBuilder here

        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Models.Devices>().HasKey(d => d.GameId);
        modelBuilder.Entity<Models.Players>().HasKey(p => p.TeamId);
        modelBuilder.Entity<Models.Teams>().HasKey(t => t.GameId);
        modelBuilder.Entity<Models.Scenario>().HasKey(s => s.GameId);

        modelBuilder.Entity<Models.Game>().HasOptional<Models.Teams>(g => g.Teams).WithRequired(t => t.Game);
        modelBuilder.Entity<Models.Game>().HasOptional<Models.Scenario>(g => g.Scenario).WithRequired(s => s.Game);
        modelBuilder.Entity<Models.Game>().HasOptional<Models.Devices>(g => g.Devices).WithRequired(d => d.Game);

    }
}
 public static class GameService
{
    public static List<Models.Game> GetGames()
    {
        using (var gctx = new Contexts.GameContext())
        {
            return gctx.Games.ToList();
        }
    }

    public static void InsertGame(Models.Game game)
    {
        using (var gctx = new Contexts.GameContext())
        {
            gctx.Games.Add(game);
            gctx.SaveChanges();
        }
    }
}

I'm trying to use it all like this:

List<Models.Game> games = Services.GameService.GetGames().ToList();

        foreach(var game in games)
        {
            Console.WriteLine("Game " + game.GameId);

            foreach (var team in game.Teams)
            {
                Console.Write("\t");
                Console.WriteLine("Team" + team.Number);
                foreach(var player in team.Players)
                {
                    Console.Write("\t\t");
                    Console.WriteLine("Player" + player.PlayerId);
                }
            }
        }

When I run this code i see my games, teams for that games, but i can't reach players for each team. So my question is: what I'm doing wrong here?


Solution

  • OK, I resolved my problem. There were few reasons which caused the problem.

    1. Need to use Include for Eager Loading. Method looks like that:

      public static List<Models.Game> GetGames()
      {
          using (var gctx = new Contexts.DatabaseContext())
          {
      
              return gctx.Games.Include(g => g.Teams).Include(g => g.Teams.TeamsList.Select(t => t.Players)).ToList();
          }
      }
      
    2. I used Fluent API to determine relationships (overriding DatabaseContext.OnModelCreating):

      protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
      
          modelBuilder.Entity<Models.Game>().HasOptional(g => g.Teams).WithOptionalPrincipal(t => t.Game); // 1 -> 0..1
          modelBuilder.Entity<Models.Game>().HasOptional(g => g.Devices).WithOptionalPrincipal(d => d.Game); // 1 -> 0..1
          modelBuilder.Entity<Models.Game>().HasOptional(g => g.Scenario).WithOptionalPrincipal(s => s.Game); // 1-> 0..1
      
          modelBuilder.Entity<Models.Teams>().HasMany(ts => ts.TeamsList).WithRequired(t => t.Teams); // 1 -> many
          modelBuilder.Entity<Models.Team>().HasMany(t => t.Players).WithRequired(p => p.Team); // 1 -> many
      
          base.OnModelCreating(modelBuilder);
      
      
      }
      
    3. Only in Game class navigation properties are NOT virtual.

    Thanks for any help in this case. You're wonderful, guys!