实体框架代码First Class,其父类和子类与其自己的类相同

时间:2012-02-11 14:59:55

标签: sql entity-framework entity-framework-4.1 ef-code-first entity-relationship

我有一类Content,它应该能够有一个parentId用于继承,但我希望它有一个子内容列表,这与这个继承树无关。

我基本上想要一个链接表作为ChildContentRelationship,其中包含parentContent和childContent的Id,而Content类将有一个ChildContentRelationship列表。

这导致了很多错误。

这是我想做的事情

public class Content
{
    public int Id { get; set; }

    public int? ParentContentId { get; set; }
    public virtual Content ParentContent { get; set; }

    public string Name { get; set; }

    public int ContentTypeId { get; set; }
    public virtual ContentType ContentType { get; set; }

    public virtual ICollection<Property> Properties { get; set; }

    public virtual ICollection<ChildContentRelationship> ChildContent { get; set; } 
}

我如何在EF中设置它?

1 个答案:

答案 0 :(得分:18)

我不确定我是否正确理解您的模型。我们来讨论一下这些选项。

暂时我省略了这个额外的实体ChildContentRelationship,我认为ChildContent集合的类型为ICollection<Content>

  • 选项1:

    我认为ParentContentChildContent反向属性。这意味着,如果您的Content Id = x且此内容的ChildContentId = y,那么ChildContents ParentContentId必须始终为X。这只是一个关联,ParentContentChildContent是同一关联的终点。

    可以使用数据注释创建此关系的映射...

    [InverseProperty("ParentContent")]
    public virtual ICollection<Content> ChildContent { get; set; }
    

    ...或使用Fluent API:

    modelBuilder.Entity<Content>()
        .HasOptional(c => c.ParentContent)
        .WithMany(c => c.ChildContent)
        .HasForeignKey(c => c.ParentContentId);
    

    我认为这不是你想要的(&#34; ......与...无关&#34; )。考虑重命名导航属性。如果有人阅读Parent...Child...,他很可能会假设他们为同一关系构建了一对导航属性。

  • 选项2:

    ParentContent不是ChildContent的反向属性,这意味着您实际上有两个独立的关系,并且两个关系的第二个端点都没有在您的模型类中公开。

    ParentContent的映射如下所示:

    modelBuilder.Entity<Content>()
        .HasOptional(c => c.ParentContent)
        .WithMany()
        .HasForeignKey(c => c.ParentContentId);
    
    不带参数的

    WithMany()表示第二个端点不是模型类中的属性,尤其是不是 ChildContent

    现在,问题仍然存在:ChildContent属于什么样的关系?它是一对多还是多对多的关系?

    • 选项2a

      如果Content引用其他ChildContent并且不能成为第二个Content,则会引用相同的ChildContent(一个Content 唯一,可以这么说)那么你就有了一对多的关系。 (这类似于订单和订单商品之间的关系:订单商品只能属于一个特定订单。)

      ChildContent的映射如下所示:

      modelBuilder.Entity<Content>()
          .HasMany(c => c.ChildContent)
          .WithOptional(); // or WithRequired()
      

      在数据库的Content表中,您将拥有一个额外的外键列,该列属于此关联,但在实体类中没有相应的FK属性。

    • 选项2b

      如果许多Content可以引用相同的ChildContent,那么您就拥有多对多的关系。 (这类似于用户和角色之间的关系:同一角色中可以有许多用户,用户可以拥有多个角色。)

      ChildContent的映射如下所示:

      modelBuilder.Entity<Content>()
          .HasMany(c => c.ChildContent)
          .WithMany()
          .Map(x =>
          {
              x.MapLeftKey("ParentId");
              x.MapRightKey("ChildId");
              x.ToTable("ChildContentRelationships");
          });
      

      此映射将在数据库中创建联接表ChildContentRelationships,但您不需要此表的相应实体。

    • 选项2c

      仅在多对多关系除了两个键(ParentIdChildId)之外还有更多属性的情况下(例如CreationDate或{{ 1}}或...)您必须在模型中引入新的实体RelationshipType

      ChildContentRelationship

      现在,您的public class ChildContentRelationship { [Key, Column(Order = 0)] public int ParentId { get; set; } [Key, Column(Order = 1)] public int ChildId { get; set; } public Content Parent { get; set; } public Content Child { get; set; } public DateTime CreationDate { get; set; } public string RelationshipType { get; set; } } 课程将收集Content s:

      ChildContentRelationship

      你有两个一对多的关系:

      public virtual ICollection<ChildContentRelationship> ChildContent
          { get; set; }
      

我相信您需要选项2a或2b,但我不确定。