zusammengesetzter Schlüssel als Fremdschlüssel

89

Ich verwende Entity Framework 4.1 in der MVC 3-Anwendung. Ich habe eine Entität, bei der der Primärschlüssel aus zwei Spalten besteht (zusammengesetzter Schlüssel). Und dies wird in einer anderen Entität als Fremdschlüssel verwendet. Wie erstelle ich die Beziehung? In normalen Scnerios verwenden wir:

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

aber was ist, wenn die Kategorie einen Schlüssel mit zwei Spalten hat?

DotnetSparrow
quelle

Antworten:

164

Sie können eine der beiden fließenden APIs verwenden:

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

    }
}

Oder Datenanmerkungen:

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
quelle
Muss ich die virtuellen Eigenschaften (öffentliche virtuelle Kategorie Kategorie {get; set;}) sowie Datenanpassungen beibehalten?
DotnetSparrow
4
virtualDie Eigenschaften der Navigation sind für das verzögerte Laden erforderlich. virtualDie Skalareigenschaften helfen bei der Änderungsverfolgung angehängter Objekte.
Ladislav Mrnka
4
Was würden Sie tun, wenn sich die Spaltennamen der Fremdschlüsseltabelle von denen im übergeordneten Element unterscheiden würden? Beispiel: Wie würden Sie im Produkt das ForeignKey-Attribut kennzeichnen, wenn die Spaltennamen wie folgt aussehen würden: PCategoryId2, PCategoryId3?
In Bezug auf diese Zeile: hat .HasRequired(p => p.Category)aber Productkeine Eigenschaft der Entität, Catagory sondern zwei IDs, die den zusammengesetzten Schlüssel einer Kategorie bilden. Kannst du das bitte erklären, denn ich glaube, es wird nicht einmal kompiliert ... Danke!
Gdoron unterstützt Monica
@gdoron: Producthat Categoryin meiner Antwort.
Ladislav Mrnka
25

Ich glaube, der einfachste Weg ist, Datenanmerkungen für die Navigationseigenschaft wie folgt zu verwenden: [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
quelle
Das hat super geklappt. Ich bevorzuge es auch, dies auf NavigationEigenschaften zu verwenden. Wie kann ich jedoch cascadeDelete: falsenur für diese Eigenschaft festlegen , nicht für die gesamte Website? Danke
RoLYroLLs
In einigen Fällen ist der Fremdschlüssel auch Teil des zusammengesetzten Schlüssels der aktuellen Tabelle. Dieser Weg hat funktioniert. Der andere Weg (@Ladislov) tat es nicht. Ich habe den Fehler "Duplicate Column Attribute"
D. Kermott
RoLYroLLs: cascadeDelete wird in der Migrationsdatei festgelegt (nach Verwendung des Befehls add-migration package manager). Ein Beispiel: AddForeignKey ("dbo.Product", "GuidedActivityID", "dbo.GuidedActivity", "ID", cascadeDelete: false);
Christophe