складений ключ як зовнішній ключ


91

Я використовую 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; }
} 

але що, якщо категорія має два стовпці ключа?

Відповіді:


169

Ви можете використовувати будь-який вільний 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; }
}

Чи потрібно зберігати віртуальні властивості (загальнодоступна категорія віртуальних категорій {get; set;}), а також оновлення даних?
DotnetSparrow

4
virtualза властивостями навігації необхідний для лінивого навантаження. virtualза скалярними властивостями допомагає відстежувати зміни прикріплених об'єктів.
Ladislav Mrnka

4
Що б ви зробили, якби назви стовпців таблиці зовнішнього ключа відрізнялися від тих, що в батьківській? Наприклад, у продукті, як би ви позначили атрибут ForeignKey, якби імена стовпців виглядали так: PCategoryId2, PCategoryId3?

Щодо цього рядка: .HasRequired(p => p.Category)але Productне має властивості Сутності, Catagory але двох ідентифікаторів, які роблять складений ключ категорії. Можете пояснити, бо я вважаю, що це навіть не буде скомпільовано ... Дякую!
gdoron підтримує Моніку

@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

У деяких випадках зовнішній ключ також є частиною складеного ключа поточної таблиці. Цей спосіб спрацював. В інший спосіб (@Ladislov) ні. Я отримав помилку: "Атрибут повторюваного стовпця"
Д. Кермотт,

RoLYroLLs: cascadeDelete встановлюється у файлі міграції (після використання команди менеджера пакунків add-migration). Приклад: AddForeignKey ("dbo.Product", "GuidedActivityID", "dbo.GuidedActivity", "ID", cascadeDelete: false);
Крістоф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.