คีย์คอมโพสิตเป็นคีย์ต่างประเทศ


93

ฉันใช้ Entity framework 4.1 ในแอปพลิเคชัน MVC 3 ฉันมีเอนทิตีที่ฉันมีคีย์หลักประกอบด้วยสองคอลัมน์ (คีย์ผสม) และกำลังใช้ในเอนทิตีอื่นเป็นคีย์ต่างประเทศ จะสร้างความสัมพันธ์ได้อย่างไร? ใน 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; }
} 

แต่ถ้าหมวดหมู่มีสองคอลัมน์ที่สำคัญ?

คำตอบ:


172

คุณสามารถใช้ 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; }
}

ฉันจำเป็นต้องเก็บคุณสมบัติเสมือน (public virtual Category Category {get; set;}) รวมทั้งคำอธิบายประกอบข้อมูลหรือไม่
DotnetSparrow

4
virtualเกี่ยวกับคุณสมบัติการนำทางเป็นสิ่งที่จำเป็นสำหรับการโหลดแบบขี้เกียจ virtualบนคุณสมบัติสเกลาร์ช่วยในการติดตามการเปลี่ยนแปลงของวัตถุที่แนบมา
Ladislav Mrnka

4
คุณจะทำอย่างไรถ้าชื่อคอลัมน์ของตารางคีย์นอกต่างจากที่อยู่ในพาเรนต์? ตัวอย่างก่อนหน้าในผลิตภัณฑ์คุณจะติดป้ายกำกับแอตทริบิวต์ ForeignKey ได้อย่างไรหากชื่อคอลัมน์ดูเหมือน: PCategoryId2, PCategoryId3

เกี่ยวกับบรรทัดนี้: .HasRequired(p => p.Category)แต่Productไม่มีคุณสมบัติของเอนทิตี Catagoryแต่มีสองรหัสที่ทำให้คีย์ผสมของหมวดหมู่ คุณช่วยอธิบายได้ไหมเพราะฉันเชื่อว่ามันจะไม่ได้รวบรวม ... ขอบคุณ!
gdoron สนับสนุน Monica

@gdoron: ProductมีCategoryในคำตอบของฉัน
Ladislav Mrnka

26

ฉันเชื่อว่าวิธีที่ง่ายที่สุดคือการใช้คำอธิบายประกอบข้อมูลในคุณสมบัติการนำทางดังนี้: [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

ในบางกรณี Foreign Key ยังเป็นส่วนหนึ่งของคีย์ผสมของตารางปัจจุบัน วิธีนี้ได้ผล วิธีอื่น (@Ladislov) ไม่ได้ ฉันได้รับข้อผิดพลาด: "Duplicate Column attribute"
D. Kermott

RoLYroLLs: cascadeDelete ถูกตั้งค่าในไฟล์การโอนย้าย (หลังจากใช้คำสั่ง add-migration package manager) ตัวอย่าง: AddForeignKey ("dbo.Product", "GuidedActivityID", "dbo.GuidedActivity", "ID", cascadeDelete: false);
Christophe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.