如何使用 code-first 正确初始化多对多关系
How to correctly initialize many to many relationship with code-first
我正在尝试使用 code-first
为我的数据库建模。
我想在这里映射的是 Users
和 Challenges
的 0 -> *
关系。
例如,用户可以有 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);
}
编辑
更新了标题和问题 - 关系不是零对多而是多对多。
该列来自您 Challenge
和 UserAccount
之间的关系。您可以在模型中声明 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 Many
和 One 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);
}
我正在尝试使用 code-first
为我的数据库建模。
我想在这里映射的是 Users
和 Challenges
的 0 -> *
关系。
例如,用户可以有 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);
}
编辑
更新了标题和问题 - 关系不是零对多而是多对多。
该列来自您 Challenge
和 UserAccount
之间的关系。您可以在模型中声明 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 Many
和 One 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 theChallenge
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);
}