kunci komposit sebagai kunci asing

91

Saya menggunakan kerangka Entitas 4.1 dalam aplikasi MVC 3. Saya memiliki entitas di mana saya memiliki kunci utama terdiri dari dua kolom (kunci komposit). Dan ini digunakan di entitas lain sebagai kunci asing. Bagaimana cara menciptakan hubungan? Dalam scnerios normal kami menggunakan:

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; }
} 

tetapi bagaimana jika kategori memiliki kunci dua kolom?

DotnetSparrow
sumber

Jawaban:

169

Anda dapat menggunakan salah satu API yang lancar:

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});

    }
}

Atau anotasi data:

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; }
}
Ladislav Mrnka
sumber
Apakah saya perlu menyimpan properti virtual (Kategori Kategori publik virtual {get; set;}) serta anovasi data?
DotnetSparrow
4
virtualpada properti navigasi diperlukan untuk pemuatan lambat. virtualpada properti skalar membantu pelacakan perubahan objek yang dilampirkan.
Ladislav Mrnka
4
Apa yang akan Anda lakukan jika nama kolom tabel kunci asing berbeda dari yang ada di induk? Misalnya, Dalam produk, bagaimana Anda akan memberi label pada atribut ForeignKey jika nama kolom terlihat seperti: PCategoryId2, PCategoryId3?
Mengenai baris ini: .HasRequired(p => p.Category)tetapi Producttidak memiliki properti Entitas Catagory tetapi dua id yang membuat kunci komposit dari sebuah kategori. Bisakah Anda jelaskan, karena saya yakin itu bahkan tidak akan bisa dikompilasi ... Terima kasih!
gdoron mendukung Monica
@gdoron: Productada Categorydi jawaban saya.
Ladislav Mrnka
26

Saya yakin cara termudah adalah menggunakan Anotasi Data pada properti Navigasi seperti ini: [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; }
}
Christophe
sumber
Ini bekerja dengan baik. Saya juga lebih suka menggunakan ini pada Navigationproperti. Namun, bagaimana cara menyetel cascadeDelete: falseuntuk properti ini saja, bukan untuk seluruh situs? Terima kasih
RoLYroLLs
Dalam beberapa kasus, kunci asing juga merupakan bagian dari kunci komposit tabel saat ini. Cara ini berhasil. Sebaliknya (@Ladislov) tidak. Saya mendapat kesalahan: "Atribut Kolom Duplikat"
D. Kermott
RoLYroLLs: cascadeDelete disetel dalam file migrasi (setelah menggunakan perintah pengelola paket tambahkan migrasi). Contoh: AddForeignKey ("dbo.Product", "GuidedActivityID", "dbo.GuidedActivity", "ID", cascadeDelete: false);
Christophe