Entity Framework 6: Code First Cascade löschen

c# entity-framework entity-framework-6 sql

Frage

Es gibt also einige ähnliche Fragen zu diesem Thema, aber ich habe immer noch Probleme zu bestimmen, was genau ich in meinem vereinfachten Szenario vermisse.

Sagen wir, ich habe die folgenden Tabellen, die geschickt nach mir benannt sind:

'JohnsParentTable' (Id, Description) 
'JohnsChildTable' (Id, JohnsParentTableId, Description)

Die resultierenden Klassen sehen so aus

public class JohnsParentTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<JohnsChildTable> JohnsChildTable { get; set; }

    public JohnsParentTable()
    {
        JohnsChildTable = new List<JohnsChildTable>();
    }
}

internal class JohnsParentTableConfiguration : EntityTypeConfiguration<JohnsParentTable>
{
    public JohnsParentTableConfiguration()
    {
        ToTable("dbo.JohnsParentTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
    }
}

public class JohnsChildTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int JohnsParentTableId { get; set; }
    public JohnsParentTable JohnsParentTable { get; set; }
}

internal class JohnsChildTableConfiguration : EntityTypeConfiguration<JohnsChildTable>
{
    public JohnsChildTableConfiguration()
    {
        ToTable("dbo.JohnsChildTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
        HasRequired(a => a.JohnsParentTable).WithMany(c => c.JohnsChildTable).HasForeignKey(a => a.JohnsParentTableId);
    }
}

In der Datenbank habe ich eine Zeile in der übergeordneten Tabelle mit einer ID von 1 zusammen mit zwei Zeilen in der untergeordneten Tabelle, die mit diesem Eltern verknüpft ist. Wenn ich das mache:

var parent = db.JohnsParentTable.FirstOrDefault(a => a.Id == 1)

Das Objekt ist korrekt ausgefüllt. Wenn ich jedoch versuche, diese Zeile zu löschen:

var parent = new Data.Models.JohnsParentTable() { Id = 1 };
db.JohnsParentTable.Attach(parent);
db.JohnsParentTable.Remove(parent);

db.SaveChanges();

Das Entitätsframework versucht Folgendes auszuführen:

DELETE [dbo].[JohnsParentTable]
WHERE ([Id] = @0)
-- @0: '1' (Type = Int32)
-- Executing at 1/23/2014 10:34:01 AM -06:00
-- Failed in 103 ms with error: The DELETE statement conflicted with the REFERENCE constraint "FK_JohnsChildTable_JohnsParentTable". The conflict occurred in database "mydatabase", table "dbo.JohnsChildTable", column 'JohnsParentTableId'.
The statement has been terminated.

Meine Frage ist dann, was ich genau vermisse, um sicherzustellen, dass Entity Framework weiß, dass es die 'JohnsChildTable'-Zeilen löschen muss, bevor das Elternteil gelöscht wird?

Akzeptierte Antwort

Dies hängt davon ab, ob Entity Framework die untergeordneten Elemente löschen soll oder ob die Datenbank dafür sorgen soll.

Wenn Sie möchten, dass EF eine Löschanweisung für alle untergeordneten Elemente generiert und diese ausführt, bevor Sie das übergeordnete Element löschen, müssen Sie zuerst alle untergeordneten Elemente in den Speicher laden.

Sie können also nicht einfach eine "Dummy" -Entität mit nur dem aufgefüllten Schlüssel erstellen und erwarten, dass die untergeordneten Elemente gelöscht werden.

Damit das funktioniert, muss die Datenbank die Löschung übernehmen.

Der Fremdschlüssel in der untergeordneten Tabelle müsste jedoch Kaskadenlöschungen aktiviert haben. Wenn dies der Fall ist, erstellt Entity Framework nur eine Löschanweisung für das übergeordnete Element, und die Datenbank weiß, dass auch die untergeordneten Elemente gelöscht werden.

Entity Framework erstellt einen Fremdschlüssel, bei dem Kaskadenlöschungen standardmäßig aktiviert sind, wenn die Beziehung wie in Ihrem Fall erforderlich ist. (Der Fremdschlüssel darf nicht null sein).

Wenn Sie die Datenbank selbst erstellt haben, müssen Sie daran denken, sie zu aktivieren.


Beliebte Antwort

Ich denke, es ist besser, die OnModelCreating-Methode zu überschreiben und diesen Code hinzuzufügen.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<JohnsChildTable>()
               .HasRequired(t=>t.JohnsParentTable)
               .WithMany(t=>t.JohnsChildTables)
               .HasForeignKey(d=>d.JohnsParentTableId)
               .WillCascadeOnDelete(true);

            base.OnModelCreating(modelBuilder);
}

Ich habe auf True WillCascadeOnDelete gesetzt (true)



Related

Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum