如何使用代码优先正确初始化多对多关系

时间:2018-01-14 22:05:27

标签: c# entity-framework ef-code-first ef-code-first-mapping

我正在尝试使用code-first来建模我的数据库。

我在这里想要映射的是0 -> *Users的{​​{1}}关系。

例如,用户可以有0或更多与之相关的挑战。挑战可以有0个或更多与之关联的用户。

这是我正在使用的代码,问题是challenge表是使用Challenges属性生成的。

UserAccount_ID

错误的属性:

enter image description here

我已经尝试将此添加到我的上下文类中,但它没有任何效果:

public class UserAccount
{
    public int Id { get; set; }
    public string Username { get; set; }

    public virtual List<Challenge> Challenges { get; set; }
}

public class Challenge
{
    public int Id { get; set; }
    public string ChallengeId {get; set;}
    public string Name { get; set; }
    public string Description { get; set; }

    public virtual List<Competitor> Competitors { get; set; }
}

public class Competitor
{
    public int Id { get; set; }
    public string Username { get; set; }
    public int Rank { get; set; }
}

修改

更新了标题和问题 - 关系不是零到多,而是多对多。

2 个答案:

答案 0 :(得分:2)

该列来自您ChallengeUserAccount之间的关系。您可以在模型中声明FK属性:

public class Challenge
{
    public int Id { get; set; }
    public string ChallengeId {get; set;}
    public string Name { get; set; }
    public string Description { get; set; }

    //Add these properties
    public int UserAccountId{get;set;}
    public UserAccount UserAccount{get;set;}

    public virtual List<Competitor> Competitors { get; set; }
}

默认情况下,EF使用一些名称约定来标识模型中的FK属性,因此该名称应该没问题。现在,如果您正在使用Fluent Api,那么我建议您按照您的意愿配置关系:

protected override void OnModelCreating(DbModelBuilder mb)
{
    mb.Entity<UserAccount>()
        .HasMany(o1 => o1.Challenges)
        .WithOptional(e=>e.UserAccount);
        .HasForeignKey(e=>e.UserAccountId);

    base.OnModelCreating(mb);
}

现在,如果您不想在Challenge实体中包含FK属性和导航属性,但想要重命名FK属性,则可以执行以下操作:

protected override void OnModelCreating(DbModelBuilder mb)
{
    mb.Entity<UserAccount>()
        .HasMany(o1 => o1.Challenges)
        .WithOptional();
        .Map(m => m.MapKey("UserAccountId"));

    base.OnModelCreating(mb);
}

更多地考虑一下你的模型,你可能真正追求的是多对多的关系,如果你能按照这种方式进行配置:

  mb.Entity<UserAccount>()
    .HasMany(r => r.Challenges)
    .WithMany() // No navigation property here
    .Map(m =>
        {
            m.MapLeftKey("UserAccountId");
            m.MapRightKey("ChallengeId");
            m.ToTable("UserAccountChallenge");
        });

答案 1 :(得分:1)

Many to Many中,有多个公约可以实现One to Manyentity framework关系。将尝试提及所有。希望这些将有所帮助。

更新(因为OP需要多对多): 许多与很多关系

第1号惯例:

  

两个模型中的集合导航属性

public class UserAccount
{
    public int Id { get; set; }
    public string Username { get; set; }

    public ICollection<Challenge> Challenges { get; set; }
}
    public class Challenge
{
   public int Id { get; set; }
   public string ChallengeId {get; set;}
   public string Name { get; set; }
   public string Description { get; set; }

   public ICollection<UserAccount> UserAccounts { get; set; }
}

实现相同的其他方式

mb.Entity<UserAccount>()
.HasMany(r => r.Challenges)
.WithMany()
.Map(m =>
    {
        m.MapLeftKey("UserAccountId");
        m.MapRightKey("ChallengeId");
        m.ToTable("UserAccountChallenge"); //Junction Table
    });

ONE to MANY Relationship

第1号惯例:

  

这可以通过包含参考导航属性来实现   在UserAccount

中输入Challenge
    public class Challenge
    {
    public int Id { get; set; }
    public string ChallengeId {get; set;}
    public string Name { get; set; }
    public string Description { get; set; }

    public UserAccount UserAccount{get;set;}    
}

第2号公约:

  

另一个惯例是包含集合导航属性   UserAccount

public class UserAccount
{
    public int Id { get; set; }
    public string Username { get; set; }

    public ICollection<Challenge> Challenges { get; set; }
}

第3号公约:

  

包括两端的导航属性也会导致   一对多的关系

public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }

public UserAccount UserAccount{get;set;}    
}

public class UserAccount
{
    public int Id { get; set; }
    public string Username { get; set; }

    public ICollection<Challenge> Challenges { get; set; }
}

第4号公约

  

两端完全定义的关系将创建一对多   关系

public class Challenge
{
  public int Id { get; set; }
  public string ChallengeId {get; set;}
  public string Name { get; set; }
  public string Description { get; set; }

  public int UserAccountId { get; set; }
  public UserAccount UserAccount{get;set;}    
}
  

使用Fluent API配置一对多关系

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // configures one-to-many relationship
    modelBuilder.Entity<UserAccount>()
        .HasRequired<Challeng>(s => s.ChallengId)
        .WithMany(g => g.UserAccount)
        .HasForeignKey<int>(s => s.ChallengId); 
}