[英]How to make M:N (many-to-many) relationship where both M and N are the same entities?
I am having difficulties with Entity Framework. 我在实体框架方面遇到了困难。 I am trying to set up datamodel with entity refering to its opposite via a connection table.
我试图通过连接表通过实体引用其对面来设置datamodel。
I have created an entity Style and connection table StyleXStyle. 我创建了一个实体样式和连接表StyleXStyle。
[Table("Styles")]
public class Style : FullAuditedEntity
{
public virtual string Name { get; set; }
public virtual string ShortName { get; set; }
public List<StyleXStyle> Opposites { get; set; } = new List<StyleXStyle>();
}
[Table("StylesXStyles")]
public class StyleXStyle: FullAuditedEntity
{
public virtual int StyleId { get; set; }
public Style Style { get; set; }
public virtual int OppositeId { get; set; }
public Style Opposite { get; set; }
}
When I try to add database migration, I got this error: 当我尝试添加数据库迁移时,我收到此错误:
Unable to determine the relationship represented by navigation property 'Style.Opposites' of type 'List<StyleXStyle>'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Since you need to self-refer to a collection of Style
entities you should have 2 collection properties for this many-to-many mapping. 由于您需要自我引用
Style
实体的集合,因此您应该为此多对多映射提供2个集合属性。 One to navigate to your opposites and one to "alikes". 一个导航到你的对立面,一个导航到“相似”。 For my examples I am including a second list property called
Alikes
. 对于我的例子,我包括一个名为
Alikes
的第二个列表属性。
With that you can include a custom mapping to tell EF how these are related: 有了它,您可以包含一个自定义映射,告诉EF这些是如何相关的:
Using attribute-based config: 使用基于属性的配置:
public class Style : FullAuditedEntity
{
[InverseProperty("Style")]
public List<StyleXStyle> Alikes { get; set; } = new List<StyleXStyle>();
[InverseProperty("Opposite")]
public List<StyleXStyle> Opposites { get; set; } = new List<StyleXStyle>();
}
public class StyleXStyle : FullAuditedEntity
{
[ForeignKey("Opposite")]
public virtual int OppositeId { get; set; }
public Style Opposite { get; set; }
[ForeignKey("Style")]
public virtual int StyleId { get; set; }
public Style Style { get; set; }
}
Using Fluent API: 使用Fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<StyleXStyle>()
.HasRequired<Style>(s => s.Style)
.WithMany(g => g.Alikes)
.HasForeignKey<int>(s => s.StyleId);
// configures one-to-many relationship
modelBuilder.Entity<StyleXStyle>()
.HasRequired<Style>(s => s.Opposite)
.WithMany(g => g.Opposites)
.HasForeignKey<int>(s => s.OppositeId);
}
The above performs the mapping on the joining entity/table so you can use that as your many-to-many relation. 以上操作在连接实体/表上执行映射,因此您可以将其用作多对多关系。 This is necessary if you need to track any information on the relation itself (for example, CreatedDate, CreatedBy, RelationDate, etc.), however, EF provides its own way to map this by convention IF you don't require additional information on the relation entity.
如果您需要跟踪关系本身的任何信息(例如,CreatedDate,CreatedBy,RelationDate等),这是必要的,但是,EF提供了自己的方式来按照约定映射它如果您不需要关于关系的其他信息关系实体。
In the latter case, you can map your entities directly to each other and omit the relation table altogether. 在后一种情况下,您可以直接将实体映射到彼此,并完全省略关系表。 Here is a quick example:
这是一个简单的例子:
[Table("Styles")]
public class Style : FullAuditedEntity
{
public virtual string Name { get; set; }
public virtual string ShortName { get; set; }
public ICollection<Style> Opposites { get; set; }
public ICollection<Style> Alikes { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Style>()
.HasMany<Style>(s => s.Alikes)
.WithMany(c => c.Opposites)
.Map(cs =>
{
cs.MapLeftKey("OppositeId");
cs.MapRightKey("StyleId");
cs.ToTable("StyleXStyle");
});
}
The code above was put together for your example, I did not fully test it but have implemented this the same way before. 上面的代码放在一起作为你的例子,我没有完全测试它,但之前以相同的方式实现了它。
HTH HTH
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.