如何使用 code-first 正确初始化多对多关系

How to correctly initialize many to many relationship with code-first

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

我想在这里映射的是 UsersChallenges0 -> * 关系。

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

这是我正在使用的代码,问题是挑战 table 是用 UserAccount_ID 属性.

生成的
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; }
}

不正确的属性:

我试过将它添加到我的上下文中 class 但它没有任何效果:

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

    base.OnModelCreating(mb);
}

编辑

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

该列来自您 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);
}

现在,如果您不想在您的挑战实体中包含 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");
        });

entity framework 中有多个实现 Many to ManyOne to Many 关系的约定。将尝试提及所有。希望这些会有所帮助。

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

约定 1:

Collection navigation properties in both models

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
    });

一对多关系

约定 1:

This can be achieved by including reference navigation property of type UserAccount in the 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:

Another convention is to include collection navigation property in UserAccount

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

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

约定 3:

Including navigation property at both ends will also result in one-to-many relationship

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:

Fully defined relationship at both ends will creates one-to-many relationship

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;}    
}

Configure One-to-Many Relationship using 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); 
}