【问题标题】:EF5 TPH Extra Foreign Keys being generated - How to get rid of them?正在生成 EF5 TPH 额外外键 - 如何摆脱它们?
【发布时间】:2013-10-02 18:36:10
【问题描述】:

这是我编写的示例应用程序,它产生的行为与我实际的更复杂的应用程序相同。 我显然在某处遗漏了一些配置方面,但我一生都无法弄清楚。出于某种原因,我的 KID 类中的每个集合都在 Sweet 表中接收自己的字段和外键......据我所知,这不是必需的......? 如何停止 EF 生成这些?

示例类、配置和生成的迁移代码如下(注意,如果我使用 TPT 而不是 TPH,则不会添加额外的字段,并且 OwnerId 可以用作关系字段)

我的课:

    public class Sweet
    {
        [Key]
        public int SweetId { get; set; }
        public string SweetName { get; set; }

        [ForeignKey("OwnerId")]
        public Kid Owner { get; set; }
        public int OwnerId { get; set; }
    }
    public class Chocolate : Sweet {}
    public class HardBoiled : Sweet {}
    public class Chewy : Sweet {}

    public class Kid
    {
        public int KidId { get; set; }
        public string FirstName { get; set; }
        public virtual ICollection<Chocolate> Chocolates { get; set; }
        public virtual ICollection<HardBoiled> BaggedSweeets { get; set; }
        public virtual ICollection<Chewy> PacketSweets { get; set; }
    }

我的配置(从 OnModelCreating 调用)

public class SweetConfiguration : EntityTypeConfiguration<Sweet>
{
    public SweetConfiguration()
    {
        Map(m => m.ToTable("Sweet"));

        Map<Chocolate>(i => i.Requires("SweetType").HasValue(1));

        Map<Chewy>(i => i.Requires("SweetType").HasValue(2));

        Map<HardBoiled>(f => f.Requires("SweetType").HasValue(3));
    }
}

生成的迁移代码:

    public override void Up()
    {
        CreateTable(
            "dbo.Kid",
            c => new
                {
                    KidId = c.Int(nullable: false, identity: true),
                    FirstName = c.String(),
                })
            .PrimaryKey(t => t.KidId);

        CreateTable(
            "dbo.Sweet",
            c => new
                {
                    SweetId = c.Int(nullable: false, identity: true),
                    SweetName = c.String(),
                    OwnerId = c.Int(nullable: false),
                    Kid_KidId = c.Int(), <--- DON'T NEED THIS
                    Kid_KidId1 = c.Int(), <--- OR THIS
                    Kid_KidId2 = c.Int(), <-- OR THIS!
                    SweetType = c.Int(),
                })
            .PrimaryKey(t => t.SweetId)
            .ForeignKey("dbo.Kid", t => t.Kid_KidId)  <!-- LIKEWISE FOR THESE THREE KEYS
            .ForeignKey("dbo.Kid", t => t.Kid_KidId1)
            .ForeignKey("dbo.Kid", t => t.Kid_KidId2)
            .ForeignKey("dbo.Kid", t => t.OwnerId, cascadeDelete: true)
            .Index(t => t.Kid_KidId)
            .Index(t => t.Kid_KidId1)
            .Index(t => t.Kid_KidId2)
            .Index(t => t.OwnerId);

    }

更新:

由于不支持我当前的模型,我已经像这样更改了我的 Kid 类:

public class Kid
{
    public int KidId { get; set; }
    public string FirstName { get; set; }
    public virtual ICollection<Sweet> Sweets { get; set; }

    [NotMapped]
    public ICollection<HardBoiled> BaggedSweets
    {
        get
        {
            return Sweets.OfType<HardBoiled>().ToList();
        }
    }
    ... and two more read-only NotMapped properties for the other collections...
}

【问题讨论】:

    标签: ef-code-first entity-framework-5 table-per-type table-per-hierarchy


    【解决方案1】:

    您不能在此模型中使用三个集合。 EF 期望反向属性和 FK 属性(OwnerOwnerId)直接在集合所引用的类中声明(即在 ChocolateHardBoiledChewy ) 而不是在基类中。要使其工作并且只有一个外键,您只能在 Kid 中定义一个导航集合,该集合引用在其中声明 OwnerOwnerId 的基类:

    public class Kid
    {
        public int KidId { get; set; }
        public string FirstName { get; set; }
        public virtual ICollection<Sweet> Sweets { get; set; }
    }
    

    (顺便说一句,您可以使用 Sweets.OfType&lt;Chocolate&gt;() 等从该集合中提取特定类型)

    TPT 也是如此。您是否有可能在 TPT 测试中没有 SweetConfigurationDbSet&lt;Sweet&gt;?这将导致模型完全没有继承(从 EF 的角度来看),因为基类 Sweet 的所有属性都将添加到三个子表中。

    【讨论】:

    • 在我的实际代码中,Sweet 是一个抽象类,所以我不在任何地方使用它——但我明白你关于不继承的观点。这个问题是 EF 特有的吗?其他 ORM 可以应付这种类型的模型吗?
    • @DaveR:我不知道其他 ORM 是否可以像您想映射它们一样映射这些类。在我看来,使用单个 Sweets 集合并不是什么大损失,因为您始终可以将子类从集合中过滤掉。如果您愿意,即使在 Kid 中使用三个附加(未映射)只读属性(仅使用 getter),它们将 Sweets.OfType&lt;Chocolate&gt;() 返回为 IEnumerable&lt;Chocolate&gt; 等。
    • 是的。已经编辑了我的答案以显示我是如何做到的。感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 2015-08-08
    • 2011-01-17
    • 2011-04-21
    • 1970-01-01
    • 2015-11-19
    • 1970-01-01
    相关资源
    最近更新 更多