简体   繁体   English

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

[英]Entity Framework - list of items is not loading

I'm trying to save games in database with EntityFramework Code-First.我正在尝试使用 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?所以我的问题是:我在这里做错了什么?

OK, I resolved my problem. 好,我解决了我的问题。 There were few reasons which caused the problem. 造成该问题的原因很少。

  1. Need to use Include for Eager Loading. 需要使用Include进行急切加载。 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): 我使用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); } 
  3. Only in Game class navigation properties are NOT virtual. 仅在Game类中,导航属性不是虚拟的。

Thanks for any help in this case. 感谢您在这种情况下的任何帮助。 You're wonderful, guys! 你们真棒!

You should add the virtual keyword to your navigation properties, that is, the properties that will be automatically filled by EF. 您应该将virtual关键字添加到导航属性中,即EF将自动填充的属性。 Specially if you are using lazy loading. 特别是如果您使用的是延迟加载。 If a property is not declared as virtual then EF will not be able to replace it by a proxy, and so the lazy loading will not work. 如果未将属性声明为虚拟属性,则EF将无法用代理替换它,因此延迟加载将无法进行。 You will not get exceptions, but the data will not be loaded. 您不会获得异常,但是不会加载数据。 Try that with the Players list property: 尝试使用“ Players列表属性:

public virtual List<Player> Players 

Also, your model is a bit strange. 另外,您的模型有点奇怪。 The keys in the entities are supposed to be identifiers for the entity itself, something like this: 实体中的键应该是实体本身的标识符,如下所示:

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

That is because they will be the primary keys for those entities. 那是因为它们将成为这些实体的主键。 You are using them instead more like foreign keys. 您正在使用它们,而更像是外键。

Entity Framework lazy loads objects. 实体框架延迟加载对象。

That is, it doesn't actually load each Player object in the Team object within the Game object. 也就是说,它实际上并未加载Game对象内Team对象中的每个Player对象。 Rather it returns a proxy to it. 而是返回它的代理。

Try returning an IQueryable in the GetGames() method: 尝试在GetGames()方法中返回一个IQueryable

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

I'm also migrating from ASPNET MVC 5 to .NET Core 6我也在从 ASPNET MVC 5 迁移到 .NET Core 6

  1. Search your whole project for : DbContext , it will find your data context class.在整个项目中搜索: DbContext ,它将找到您的数据上下文 class。

  2. Notice that this class found also has some methods that return DBSet .请注意,这个 class 发现也有一些返回DBSet的方法。 These are the Models that represent tables in the database and you can access those directly.这些是代表数据库中表的模型,您可以直接访问它们。

  3. Import your data context class as a private property of your controllers like:将您的数据上下文 class 作为控制器的私有属性导入,例如:

    private readonly SampleDbContext _context;私有只读 SampleDbContext _context;

  4. Access your models (DBSets) with chained methods.使用链式方法访问您的模型 (DBSet)。 Query example to return single user:返回单个用户的查询示例:

    _context.Users.FirstOrDefault(u => u.Name == input.Name); _context.Users.FirstOrDefault(u => u.Name == input.Name);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM