实体框架-项目列表未加载

本文关键字:加载 列表 项目 框架 实体 | 更新日期: 2023-09-27 18:14:05

我试图在数据库中保存游戏与EntityFramework Code-First。

有我的类的片段:

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

和实体框架部分:

 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();
        }
    }
}

我试着像这样使用它:

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

当我运行这段代码时,我可以看到我的游戏,该游戏的团队,但我无法访问每个团队的玩家。所以我的问题是:我做错了什么?

实体框架-项目列表未加载

好了,我的问题解决了。引起这个问题的原因很少。

  1. 需要使用Include for Eager Loading。方法看起来像这样:

    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. 我使用Fluent API来确定关系(覆盖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);
    
    }
    
在这种情况下,谢谢你的帮助。你们太棒了,伙计们!

您应该将virtual关键字添加到您的导航属性中,即EF将自动填充的属性。特别是在使用延迟加载的情况下。如果一个属性没有被声明为虚属性,那么EF将无法用代理替换它,因此延迟加载将不起作用。您不会得到异常,但不会加载数据。试试Players list属性:

public virtual List<Player> Players 

还有,你们的模型有点奇怪。实体中的键应该是实体本身的标识符,像这样:

modelBuilder.Entity<Game>().HasKey(g => g.GameId);
modelBuilder.Entity<Team>().HasKey(t => t.TeamId);
modelBuilder.Entity<Player>().HasKey(p => p.PlayerId);

这是因为它们将是这些实体的主键。

实体框架延迟加载对象。

也就是说,它实际上并没有在Game对象中加载Team对象中的每个Player对象。相反,它返回一个代理给它。

尝试在GetGames()方法中返回IQueryable:

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

我也正在从asp.net MVC 5迁移到。net Core 6

  1. 在整个项目中搜索: DbContext,它会找到你的数据上下文类。

  2. 注意这个类也有一些返回DBSet的方法。这些是代表数据库中的表的模型,您可以直接访问它们。

  3. 导入数据上下文类作为控制器的私有属性,如:

    private readonly SampleDbContext;

  4. 使用链式方法访问模型(DBSets)。返回单个用户的查询示例:

    _context.Users。FirstOrDefault (u =比;u.Name == input.Name);