【问题标题】:EF models. Navigation properties can only participate in a single relationship英孚模型。导航属性只能参与单个关系
【发布时间】:2019-12-10 20:26:23
【问题描述】:

我有这样的实体,它们紧密相连。

public class Game
{
    public int Id { get; set; }

    public int FirstTeamId { get; set; }
    public Team FirstTeam { get; set; }
    public int SecondTeamId { get; set; }
    public Team SecondTeam { get; set; }

    public Stadium Stadium { get; set; }
    public DateTime Date { get; set; }

    public GameStatus Result { get; set; }

    public Game(DateTime date , GameStatus result )
    {
        Date = date;
        Result = result;
    }
}

public class Player
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public DateTime Birthday { get; set; }
    public PlayerStatus Status { get; set; }
    public PlayerHealthStatus HealthStatus { get; set; }
    public int Salary { get; set; }
    public int TeamId { get; set; }
    public Team Team { get; set; }

    public Player(string name , string surname, DateTime birthday, PlayerStatus status, PlayerHealthStatus healthStatus, int salary)
    {
        Name = name;
        Surname = surname;
        Birthday = birthday;
        Status = status;
        HealthStatus = healthStatus;
        Salary = salary;
    }

}

public class Stadium
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Capacity { get; set; }
    public int PriceForPlace { get; set; }

    public Stadium(string name, int capacity, int priceForPlace)
    {
        Name = name;
        Capacity = capacity;
        PriceForPlace = priceForPlace;
    }
}

public class Team
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Player> Players { get; set; }

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

    public Team(string name)
    {
        Name = name;
    }

    public Team(string name, List<Player> players) : this(name)
    {
        Players = players;

    }
}

在我的 Context 类中,我试图描述我的类之间的关系。但有些地方不正确。

public class ApplicationContext : DbContext
{
    public DbSet<Player> Players { get; set; }
    public DbSet<Game> Games { get; set; }
    public DbSet<Team> Teams { get; set; }
    public DbSet<Stadium> Stadiums { get; set; }

    public ApplicationContext()
    {
        Database.EnsureCreated();
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=best-komp;Database=FootballApplicationDataBase;Trusted_Connection=True;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Player>()
            .HasOne(p => p.Team)
            .WithMany(t => t.Players)
            .HasForeignKey(p => p.TeamId)
            .HasPrincipalKey(t => t.Id);
        modelBuilder.Entity<Team>()
            .HasMany(p => p.Players)
            .WithOne(p => p.Team)
            .HasForeignKey(p => p.TeamId)
            .HasPrincipalKey(t => t.Id);

        modelBuilder.Entity<Game>()
            .HasOne(g => g.FirstTeam)
            .WithMany(t => t.Games)
            .HasForeignKey(t => t.FirstTeamId)
            .HasPrincipalKey(t => t.Id);
        modelBuilder.Entity<Game>()
            .HasOne(g => g.SecondTeam)
            .WithMany(t => t.Games)
            .HasForeignKey(t => t.SecondTeamId)
            .HasPrincipalKey(t => t.Id);


    }
}

这段代码有什么问题?因为我有“导航属性只能参与单个关系”。当我尝试用我的 ApplicationContext 做某事时出错。

【问题讨论】:

    标签: c# entity-framework entity-framework-core


    【解决方案1】:

    您不能将Team.Games 重复用作Game.FirstTeam 和Team.SecondTeam 的逆属性。想想看,如果你把比赛加到Team.Games,EF怎么知道是哪支球队,第一名还是第二名?

    您需要两个集合来描述这些关系。这也是为类模型添加更多含义的机会。例如(仅修改代码):

    public class Game
    {
        ...
        public int HomeTeamId { get; set; }
        public Team HomeTeam { get; set; }
        public int AwayTeamId { get; set; }
        public Team AwayTeam { get; set; }
    }
    
    public class Team
    {
        ...
        public List<Game> HomeGames { get; set; }
        public List<Game> AwayGames { get; set; }
    }
    

    对于一支球队来说,区分主客场比赛很有意义,例如比较两种比赛的结果。

    还有映射:

    modelBuilder.Entity<Game>()
        .HasOne(g => g.HomeTeam)
        .WithMany(t => t.HomeGames)
        .HasForeignKey(t => t.HomeTeamId)
        .HasPrincipalKey(t => t.Id);
    modelBuilder.Entity<Game>()
        .HasOne(g => g.AwayTeam)
        .WithMany(t => t.AwayGames)
        .HasForeignKey(t => t.AwayTeamId).OnDelete(DeleteBehavior.NoAction)
        .HasPrincipalKey(t => t.Id);
    

    如果使用 Sql Server,这个删除行为指令对于防止不允许的多个级联路径是必要的。

    【讨论】:

    • 也许你可以帮助我的所有模型使用这个模型构建器,因为在某些情况下我没有模型之间的参考
    • 只需提出一个新问题来解释其中一种情况。
    • 这是否意味着Game.HomeTeamId 和Game.AwayTeamId 将在提取的对象上可用并作为数据库中的列?但只会设置一个,具体取决于它在Team 中“添加”到哪个列表?
    • 也许我遗漏了一些东西,但我不同意 EF 在添加到 Team.Games 时无法知道团队是第一还是第二的想法。每个Game 都有FirstTeamId 和SecondTeamId,并且配置清楚地表明,对于Game,如果外键Game.FirstTeamId=Team.Id 添加这个Game 引用到属性Game.FirstTeam 和SecondTeam 也一样(在这种情况下可以是 FirstTeam == SecondTeam,为什么不呢)。我认为这种行为/配置现在不受支持,但并非不可能。这不是一个无法决定的任务。
    • @JanDrozen 是的,如果 EF 支持这一点,也许它可以解决这个问题。既然没有,我们就不能尝试。但在大多数情况下,EF 允许开发人员将对象添加到集合或设置引用导航属性,而无需担心正确的 ID。这个想法是 EF 在保存对象图时计算出 ID。必须添加具有正确 ID 集的 Game 实例将违反此原则。
    【解决方案2】:

    问题是您的 Team 模型与您的 Game 模型有 2 个一对多的关系,但您在 Team 上只有一个导航属性。

    您需要在 Team 模型上有 2 个导航属性,每个关系一个。 (游戏 1、游戏 2...)。

    您还需要在 Game 模型中定义这些关系 - 每个关系的 Team 属性。

    查看this 答案以获取更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      • 2011-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      相关资源
      最近更新 更多