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

Dea*_*lan 7 sql entity-relationship entity-framework ef-code-first entity-framework-4.1

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

我基本上想要一个链接表作为ChildContentRelationship与Id的parentContent和childContent在其中,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; } 
}
Run Code Online (Sandbox Code Playgroud)

我如何在EF中设置它?

Sla*_*uma 18

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

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

  • 选项1:

    我认为ParentContent逆属性ChildContent.这意味着如果你有一个Contentwith Id= x并且这个Content有一个ChildContentwith Id= y那么ChildContents ParentContentId必须总是x.这只是一个关联,ParentContent并且ChildContent是同一关联的端点.

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

    [InverseProperty("ParentContent")]
    public virtual ICollection<Content> ChildContent { get; set; }
    
    Run Code Online (Sandbox Code Playgroud)

    ...或使用Fluent API:

    modelBuilder.Entity<Content>()
        .HasOptional(c => c.ParentContent)
        .WithMany(c => c.ChildContent)
        .HasForeignKey(c => c.ParentContentId);
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 选项2:

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

    映射ParentContent将如下所示:

    modelBuilder.Entity<Content>()
        .HasOptional(c => c.ParentContent)
        .WithMany()
        .HasForeignKey(c => c.ParentContentId);
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    • 选项2a

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

      映射ChildContent将如下所示:

      modelBuilder.Entity<Content>()
          .HasMany(c => c.ChildContent)
          .WithOptional(); // or WithRequired()
      
      Run Code Online (Sandbox Code Playgroud)

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

    • 选项2b

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

      映射ChildContent将如下所示:

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

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

    • 选项2c

      只有在多对多关系除了两个键(ParentIdChildId)之外还有更多属性的情况下(例如CreationDate,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; }
      }
      
      Run Code Online (Sandbox Code Playgroud)

      现在你的Content班级将有一个ChildContentRelationships 的集合:

      public virtual ICollection<ChildContentRelationship> ChildContent
          { get; set; }
      
      Run Code Online (Sandbox Code Playgroud)

      你有两个一对多的关系:

      modelBuilder.Entity<ChildContentRelationship>()
          .HasRequired(ccr => ccr.Parent)
          .WithMany(c => c.ChildContent)
          .HasForeignKey(ccr => ccr.ParentId);
      
      modelBuilder.Entity<ChildContentRelationship>()
          .HasRequired(ccr => ccr.Child)
          .WithMany()
          .HasForeignKey(ccr => ccr.ChildId);
      
      Run Code Online (Sandbox Code Playgroud)

我相信你想要2a或2b选项,但我不确定.

  • 感谢清除它,我想我正在寻找选项2b,也许命名需求得到了解决.我认为它更加逼真,因此可能需要不同的类/设计.我明天会试试. (2认同)