两个类之间的实体框架多对多

本文关键字:实体 框架 之间 两个 | 更新日期: 2023-09-27 17:54:59

我正在开发一个简单的MVC应用程序,使用实体框架来跟踪羽毛球联赛的分数。我有以下两类:

public class Game
{
    public int Id { get; set; }
    public Player Player1 { get; set; }
    public Player Player2 { get; set; }
    public int Player1Score { get; set; }
    public int Player2Score { get; set; }
}

public class Player
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public List<Game> Games { get; set; }
}

我遇到的问题是,当我有一个玩家的实例时,Games属性会返回一个空列表。当我请求我的玩家列表时,我使用以下内容:-

var players = badmintonDB.Players.Include("Games").ToList();

通过对SO的搜索,我试图覆盖OnModelCreating。我已经尝试了以下使用和不使用Map()的操作。这在我的数据库中创建了另一个表,但它不包含任何记录。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Player>().HasMany(p => p.Games).WithMany()
            .Map(m =>
            {
                m.ToTable("PlayerGames");
                m.MapLeftKey("Player_Id");
                m.MapRightKey("Game_Id");
            });
        base.OnModelCreating(modelBuilder);
    }

我看不出哪里出了问题,是需要重新思考POCO的设计,还是在重写OnModelCreating时语法错误。

如有任何帮助,我们将不胜感激。

两个类之间的实体框架多对多

我不确定这个设计是否能按照你想要的方式工作。如果你制作了一个新的"Score"实体来将玩家与这样的游戏联系起来呢:

public class Game
{
    public int Id { get; set; }
    public virtual ICollection<Score> Scores { get; set; }
}
public class Player
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public virtual ICollection<Score> Scores { get; set; }
}
public class Score
{
    public int ScoreId { get; set; }
    public virtual  Player Player { get; set; }
    public virtual Game Game { get; set; }
    public int Score { get; set; }
}

更新:
仔细想想,我不确定这是否可以通过自动导航属性实现。原因是:您在Game中有两个外键。因此,玩家要加载其游戏列表,EF必须在两个外键上创建一个选择。

旧答案(我现在认为是错误的(:
EF尝试自动检测导航属性。也许这失败了,因为Game有两个Player

自己声明导航:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder
         .Entity<Game>()
         .HasRequired(g => g.Player1)
         .WithMany()
         .WillCascadeOnDelete(false);
        modelBuilder
         .Entity<Game>()
         .HasRequired(g => g.Player2)
         .WithMany()
         .WillCascadeOnDelete(false);
        base.OnModelCreating(modelBuilder);
    }

请尝试:

public virtual List<Game> Games { get; set; }

对于代码优先的API,如果要使用延迟加载,则需要将导航属性指定为virtual。请参阅C#EF Code First虚拟关键字,它有什么作用?

public class Player
{
    public Player()
    {
        this.Games = new List<Game>();
    }
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public List<Game> Games { get; set; }
}

如果启用了延迟加载,并且您没有像使用Map();那样修改任何关系,则var players = badmintonDB.Players;应返回所有玩家及其关联的所有游戏。

但是要注意,当使用延迟加载加载数据时,它实际上取决于您的输出。如果你愿意,例如输出JSON字符串中的所有数据,它将加载所有游戏。如果没有,它不会打扰,因为它会认为你不需要任何游戏来展示。