为了使用
Database-First approach
创建多对多关系,你需要设置符合以下规则的数据库架构:
- 创建一个带有
ProductID
列作为主键的Products
表
- 创建一个带有
ProductID
列和RelatedID
列,并将两个列都标记为主键(复合主键)的ProductRelations
表
- 不要在
ProductRelations
表中添加任何其他列。这两个关键列必须是表中唯一的列,以便让EF将此表识别为用于多对多关系的链接表
- 在两个表之间创建两个外键关系:
- 第一个关系将
Products
表作为主键表,使用ProductID
作为主键,将ProductRelations
表作为外键表,仅使用ProductID
作为外键
- 第二个关系也将
Products
表作为主键表,使用ProductID
作为主键,将ProductRelations
表作为外键表,仅使用RelatedID
作为外键
- 为前两个关系启用级联删除。(你不能同时将两个关系都启用,因为SQL Server不允许这样做,否则会导致多个级联删除路径。)
如果现在从这两个表生成实体数据模型,你将只得到一个实体,即一个Product
实体(如果禁用单数化,则可能是Products
)。 链接表ProductRelations
将不会公开为实体。
Product
实体将具有两个导航属性:
public EntityCollection<Product> Products { get { ... } set { ... } }
public EntityCollection<Product> Products1 { get { ... } set { ... } }
这些导航集合是同一多对多关系的两个端点。(如果您想要通过多对多关系连接两个不同的表,例如表
A
和
B
,则一个导航集合(
Bs
)将在实体
A
中,另一个(
As
)将在实体
B
中。但因为您的关系是"自引用",所以两个导航属性都在实体
Product
中。)
这两个属性的含义是:
Products
是与给定产品相关的产品,
Products1
是指向给定产品的产品。例如: 如果关系意味着一个产品需要其他产品作为零件进行制造,并且您拥有产品“笔记本电脑”、“处理器”、“硅片”,那么“处理器”由“硅片”制成(“硅片”是产品实体
Processor
的
Products
集合中的一个元素),并被“笔记本电脑”使用(“笔记本电脑”是产品实体
Processor
的
Products1
集合中的一个元素)。取名为
MadeOf
和
UsedBy
会更加合适。
如果您只对关系的一侧感兴趣,可以安全地从生成的模型中删除其中一个集合。例如,在模型设计器表面上删除
Products1
即可。您还可以重命名属性,关系仍将是多对多。
编辑
如评论所要求,使用
Code-First
方法实现的模型和映射如下:
模型:
public class Product
{
public int ProductID { get; set; }
public ICollection<Product> RelatedProducts { get; set; }
}
映射:
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasMany(p => RelatedProducts)
.WithMany()
.Map(m =>
{
m.MapLeftKey("ProductID");
m.MapRightKey("RelatedID");
m.ToTable("product_related");
});
}
}