复合键作为外键


90

我在MVC 3应用程序中使用Entity Framework 4.1。我有一个实体,我的主键由两列组成(复合键)。这在另一个实体中用作外键。如何建立关系?在普通的scnerios中,我们使用:

public class Category
{
    public string CategoryId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string CategoryId { get; set; }

    public virtual Category Category { get; set; }
} 

但是如果category有两列键怎么办?

Answers:


168

您可以使用任何一种流畅的API:

public class Category
{
    public int CategoryId1 { get; set; }
    public int CategoryId2 { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public int CategoryId1 { get; set; }
    public int CategoryId2 { get; set; }

    public virtual Category Category { get; set; }
}

public class Context : DbContext
{
    public DbSet<Category> Categories { get; set; }
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Category>()
            .HasKey(c => new {c.CategoryId1, c.CategoryId2});

        modelBuilder.Entity<Product>()
            .HasRequired(p => p.Category)
            .WithMany(c => c.Products)
            .HasForeignKey(p => new {p.CategoryId1, p.CategoryId2});

    }
}

或数据注释:

public class Category
{
    [Key, Column(Order = 0)]
    public int CategoryId2 { get; set; }
    [Key, Column(Order = 1)]
    public int CategoryId3 { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    [Key]
    public int ProductId { get; set; }
    public string Name { get; set; }
    [ForeignKey("Category"), Column(Order = 0)]
    public int CategoryId2 { get; set; }
    [ForeignKey("Category"), Column(Order = 1)]
    public int CategoryId3 { get; set; }

    public virtual Category Category { get; set; }
}

我是否需要保留虚拟属性(公共虚拟类别Category {get; set;})以及数据更新?
DotnetSparrow

4
virtual导航属性是延迟加载所必需的。virtual标量属性上的on有助于跟踪附加对象的变化。
Ladislav Mrnka 2011年

4
如果外键表的列名与父表中的列名不同,该怎么办?例如,在产品中,如果列名看起来像PCategoryId2,PCategoryId3,您将如何标记ForeignKey属性?

关于这一行:.HasRequired(p => p.Category)Product没有Entity 的属性,Catagory而是两个ID,它们构成一个类别的组合键。您能解释一下吗,因为我相信它甚至不会编译...谢谢!
gdoron在2012年

@gdoron:ProductCategory我的答案。
拉迪斯拉夫·姆恩卡

25

我相信最简单的方法是在Navigation属性上使用数据注释,如下所示: [ForeignKey("CategoryId1, CategoryId2")]

public class Category
{
    [Key, Column(Order = 0)]
    public int CategoryId1 { get; set; }
    [Key, Column(Order = 1)]
    public int CategoryId2 { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
    [Key]
    public int ProductId { get; set; }
    public string Name { get; set; }
    public int CategoryId1 { get; set; }
    public int CategoryId2 { get; set; }

    [ForeignKey("CategoryId1, CategoryId2")]
    public virtual Category Category { get; set; }
}

这很棒。我也更喜欢在Navigation属性上使用它。但是,如何cascadeDelete: false仅为此属性设置,而不是整个站点设置?谢谢
RoLYroLLs

在某些情况下,外键也是当前表的组合键的一部分。这种方式有效。另一种方式(@Ladislov)没有。我收到错误:“重复列属性”
D. Kermott

RoLYroLLs:在迁移文件(使用add-migration软件包管理器命令后)中设置了级联删除。示例:AddForeignKey(“ dbo.Product”,“ GuidedActivityID”,“ dbo.GuidedActivity”,“ ID”,级联删除:false);
克里斯多夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.