在EF Code First中映射同一对象上的多个外键

时间:2012-03-02 16:10:03

标签: asp.net-mvc-3 entity-framework ef-code-first

我是EF的新手,我刚刚开始了一个新项目。我目前有一个模型BrandManagers,其中包含一个主键和三个外键。我不明白我应该如何在DbContext中映射这些内容。

public class BrandManager
{
    public int BrandManagerId { get; set; }

    [Required()]
    public int PersonId { get; set; }

    [Required()]
    public int BrandId { get; set; }

    [Required()]
    public int CountryId { get; set; }

    public virtual Person Person { get; set; }
    public virtual Brand Brand { get; set; }
    public virtual Country Country { get; set; }
}

我将如何映射?我试过以下,但没有用。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .HasRequired(x => x.Country);

    modelBuilder.Entity<Brand>()
        .HasMany(x => x.BrandManagers);

    modelBuilder.Entity<BrandManager>()
        .HasRequired(x => x.Person);
    modelBuilder.Entity<BrandManager>()
        .HasRequired(x => x.Brand);
    modelBuilder.Entity<BrandManager>()
        .HasRequired(x => x.Country);

    base.OnModelCreating(modelBuilder);
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}

我一直在

  

在表'Person'上引入FOREIGN KEY约束'FK_Person_Country_CountryId'可能会导致循环或多个级联路径。

我在ASP.NET网站的介绍教程中没有找到任何解决这个问题的方法,也没有关于此问题的任何问题,所以我开始觉得我误解了一些重要的部分EF。

2 个答案:

答案 0 :(得分:2)

我的答案更具体地说明了如何在EF Code First中映射外键。当Lenalent回答并且是正确的时候,我正准备关于多个级联路径的第二部分。所以,不要丢弃我的答案,这可能对你有所帮助,这里是一般如何在EF :)中映射外键的答案。稍微介绍一下底部的级联删除。

您可以使用数据注释,而无需在模型构建器中进行映射。但是,如果您不希望POCO对象标记有数据库注释,我还使用modelBuilder提供了解决方案。

另外请注意,只要您拥有Person引用,就不需要拥有PersonId。在这种情况下,生成器会为您创建FK(并且您的POCO类将不具有它不需要的Id)。但是,使用Id进行延迟加载可能是更好的做法(我不确定这是否是你这样做的原因)。

最后,如果遵循惯例,您甚至不需要设置外键。因此,如果您的国家/地区类的PK为Id,那么当您使用CountryId创建Country引用时,EF将通过命名表明CountryId是国家/地区引用的FK。 (Source

数据注释:

public class BrandManager
{
    public int BrandManagerId { get; set; }

    [Required()]
    public int PersonId { get; set; }

    [Required()]
    public int BrandId { get; set; }

    [Required()]
    public int CountryId { get; set; }

    [ForeignKey("PersonId")]
    public virtual Person Person { get; set; }
    [ForeignKey("BrandId")]
    public virtual Brand Brand { get; set; }
    [ForeignKey("CountryId")]
    public virtual Country Country { get; set; }
}

DbContext :(另外,在这种情况下,您不应该在POCO类上需要任何数据注释,因为它们都是在模型构建器中设置的)

modelBuilder.Entity<BrandManager>()
    .HasRequired(x => x.Person)
    .WithMany(x=>x.People)
    .HasForeignKey(x=>x.PersonId);

至于你得到的具体错误,你需要添加.WillCascadeOnDelete(false)作为指向BrandManager-&gt; Country的宽容。您可以为Person-&gt; Country删除它,但最好删除BrandManager,因为它最终会通过Person路径级联。

答案 1 :(得分:1)

您遇到的问题是SqlServer问题。对于外键关系以及来自级联删除的多个删除路径,它往往非常保守。

你是从品牌经理和人的国家关系中得到的。删除国家/地区将产生两条到品牌经理的路径:

Country -> Person -> Brand Manager
Country -> Brand Manager

解决方案是删除其中一个实体的删除级联:

// Remove the cascade for country->Brand Manager.
// Let it cascade through Person instead
modelBuilder.Entity<BrandManager>()
    .HasRequired(x => x.Country)
    .WillCascadeOnDelete(false);