【问题标题】:EF: How to map multiple FKs in one junction table?EF:如何在一个联结表中映射多个 FK?
【发布时间】:2013-09-06 08:33:48
【问题描述】:

在 4.3.1 上使用代码优先的 EF 下面是一个梦幻运动工具的简单架构:

这是一个带有转折的经典多对多关系。 Player 表有一个 PlayerId+LeagueId 的复合键,以便转移到联结表。 (注意:PlayerId 在表中不是唯一的,给定联赛(例如 NFL)可能使用与不同联赛(例如 NBA)相同的 playerIds

当我尝试像这样定义映射时,出现 EF 错误:

this.HasMany(t => t.Players).WithMany(p => p.FantasyTeams).Map(mc => {
            mc.ToTable("FantasyTeam_2_Player");
            mc.MapLeftKey("PlayerId", "LeagueId");
            mc.MapRightKey("FantasyTeamId");
        });

像这样我得到一个神秘的错误:无效的列名'League_LeagueId'。

如果我左右切换我得到:指定的关联外键列“PlayerId”无效。指定的列数必须与主键列数匹配。

编辑:这里是实体

梦幻团队

    public int FantasyTeamId { get; set; }
    public string TeamName { get; set; }
    public string TeamEmail { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime LastModified { get; set; }
    public bool Active { get; set; }

    public virtual ICollection<Player> Players { get; set; }

播放器

    public virtual League League { get; set; }
    public int PlayerId { get; set; }
    public int LeagueId { get; set; }
    public string PlayerType { get; set; }
    public string Name { get; set; }
    public string Team { get; set; }
    public string Position { get; set; }

    public virtual ICollection<FantasyTeam> FantasyTeams { get; set; }

映射

public Player_Mapping() {
        this.HasKey(t => new { t.PlayerId, t.LeagueId });
        this.ToTable("Player");
        this.Property(t => t.PlayerId).HasColumnName("PlayerId").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        this.Property(t => t.LeagueId).HasColumnName("LeagueId").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        this.Property(t => t.PlayerType).HasColumnName("PlayerType").HasMaxLength(50).IsRequired();
        this.Property(t => t.Name).HasColumnName("Name").HasMaxLength(255);
        this.Property(t => t.Team).HasColumnName("Team").HasMaxLength(50);
        this.Property(t => t.Position).HasColumnName("Position").HasMaxLength(50);

    }


public FantasyTeam_Mapping() {
        this.HasKey(t => t.FantasyTeamId);
        this.ToTable("FantasyTeam");
        this.Property(t => t.FantasyTeamId).HasColumnName("FantasyTeamId").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.Property(t => t.Active).HasColumnName("Active").IsRequired();
        this.Property(t => t.CreatedDate).HasColumnName("CreatedDate").IsRequired();
        this.Property(t => t.LastModified).HasColumnName("LastModified").IsRequired();
        this.Property(t => t.TeamEmail).HasColumnName("TeamEmail").IsRequired();
        this.Property(t => t.TeamName).HasColumnName("TeamName").IsRequired();
        this.HasMany(t => t.Players).WithMany(p => p.FantasyTeams).Map(mc => {
            mc.ToTable("FantasyTeam_2_Player");
            mc.MapLeftKey("PlayerId", "LeagueId");
            mc.MapRightKey("FantasyTeamId");
        });

    }

我在这里做错了什么?

【问题讨论】:

  • 如果玩家只能在一个联赛中,为什么你需要一个 LeagueId 作为 Player 键的一部分?顺便说一句,表中的复合键不能引用另一个表中的非复合键...
  • @HenkHolterman 当然可以。 ERD 直观地显示了高级数据库模型。这些细节在代码优先中很容易丢失,并且在不了解模型或设想某种目标的情况下盲目“依赖魔法”时尤其成问题。现在,它可能不是一个正确的 ERD 配合得很好,但打折它就是丢掉一个有用的工具。 (免责声明:我相信模型优先。)
  • @user2246674 - 是的,您可以/应该在映射和数据库生成之后创建和检查一个,但这似乎是一个起点..
  • @HenkHolterman 我认为这是一个很好的起点。 ERD 可以进行可视化分析,并且在这种情况下,可以质疑和/或重新设计。然后可以探索到所选模型的映射。 EF(代码优先)方法可能没有对齐或可以利用不同的映射 - 但这并不能消除首先设计/探索模型的有用性。还可以比较初始/目标和代码优先模型的“正确性一致性”。
  • @RaphaëlAlthaus - PlayerIds 不是唯一的,它们仅在给定联赛中是唯一的。因此,例如,您可能有球员 ID 为 1、2、3、4 的 NFL 球员和球员 ID 为 1、2、3、4 的 NBA 球员

标签: c# .net entity-framework many-to-many


【解决方案1】:

嗯,我只是测试了这个(简化的),它不会抛出任何错误:

public class MyContext: DbContext
    {       
        public DbSet<League> Leagues { get; set; }
        public DbSet<Player> Players { get; set; }
        public DbSet<FantasyTeam> FantasyTeams { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<League>().HasKey(m => m.LeagueId);
            modelBuilder.Entity<Player>().HasKey(m => new { m.PlayerId, m.LeagueId })
                .HasRequired<League>(m => m.League);
            modelBuilder.Entity<FantasyTeam>().HasKey(m => m.FantasyTeamId)
                .Property(m => m.FantasyTeamId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            modelBuilder.Entity<FantasyTeam>().HasMany(t => t.Players).WithMany(p => p.FantasyTeams).Map(mc =>
            {
                mc.ToTable("FantasyTeam_2_Player");
                mc.MapLeftKey("FantasyTeamId");
                mc.MapRightKey("PlayerId", "LeagueId");
            });
            base.OnModelCreating(modelBuilder);
        }
    }

【讨论】:

  • 是的,这正是我所拥有的。在您尝试查询它之前它不会抛出任何错误,然后它会因错误“无效的列名 'League.Leauge_Id'(我的代码中不存在(注意下划线))而爆炸。另一个奇怪的事情是我可以很好地查询 Player ......像这样: dbContext.Players.SingleOrDefault(p => p.PlayerId == 123);工作正常,但对 FantasyTeam 的相同查询会爆炸
  • 嗯,你的意思是你的数据库中有数据?你是如何填充它的?您能否显示哪个查询引发了异常,而不是,也许? (我试图填充一些数据并检索它们,在这里看起来很好)。
猜你喜欢
  • 1970-01-01
  • 2019-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 2020-06-25
  • 2011-12-14
相关资源
最近更新 更多