2012-03-28 3 views
0

Ich habe die folgenden zwei Entitäten:EF 4.1 Cascading in zwei Richtungen zwischen Einheiten mit zwei Beziehungen

public class Tournament { 
    public int TournamentID { get; set; } 
    public String Name { get; set; } 
    public int? OfficialID { get; set; } 

    public virtual Official HeadOfficial { get; set; } 

    public virtual ICollection<Official> Officials { get; set; } 
} 

public class Official { 
    public int OfficialID { get; set; } 
    public String Surname { get; set; } 
    public String FirstName { get; set; } 
    public int TournamentID { get; set; } 

    public virtual Tournament Tournament { get; set; } 
} 

Ein Turnier 0..N Beamten haben kann und ein HAS offizielle ein Turnier mit ihm verbunden sein. Die zweite Beziehung ist, dass ein Turnier eine official haben kann.

Um die EF richtig dies zu machen interpretieren, wenn die Datenbank machen ich folgendes haben:

protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
     modelBuilder.Entity<Tournament>() 
      .HasOptional(t => t.HeadOfficial) 
      .WithMany() 
      .HasForeignKey(t => t.OfficialID); 

     modelBuilder.Entity<Tournament>() 
      .HasMany(t => t.Officials) 
      .WithRequired(o => o.Tournament) 
      .HasForeignKey(o => o.TournamentID);   
    } 

Wenn ich jetzt ein Turnier löschen, alle Beamten, die an diesem Turnier verknüpft wurden, gelöscht, das, was ich wollen. Wenn ich jedoch einen Offiziellen lösche, der in einem der Turniere zum offiziellen Offiziellen ernannt wurde, wird beim Löschen nicht davon ausgegangen, dass die Löschanweisung mit der Referenzbeschränkung in Turnieren.OffizielleID in Konflikt stand.

Antwort

1

Wenn ich jetzt ein Turnier lösche, werden alle Offiziellen, die mit dieses Turnier verbunden waren, gelöscht, was ich will. Wenn ich jedoch einen Offiziellen lösche, der in einem der Turniere zum offiziellen Schiedsrichter gemacht wurde, geht das Löschen nicht durch, indem zitiert wird, dass die Anweisung delete mit der Referenzeinschränkung in Tournaments.OfficialID in Konflikt steht.

Ich denke, das sind ganz andere Situationen. Der erste Fall funktioniert, weil in der Datenbank ein kaskadierendes Lösch-Setup existiert (EF hat diese Regel in der Datenbank erstellt, weil die Beziehung erforderlich ist, das ist das Standardverhalten).

Ihre zweite Beziehung ist optional, daher gibt es standardmäßig kein kaskadierendes Löschen. Wichtiger: Ich glaube nicht, dass du kaskadieren willst, weil das Löschen eines Offiziellen auch die Turniere löschen würde, die diesen Offiziellen als Kopf haben.

Ich kann mir nur vorstellen, dass Sie die HeadOfficial Referenz auf null setzen möchten, wenn der offizielle gelöscht wird. Aber es gibt keinen automatischen Weg (wie beim kaskadierenden Löschen). Sie müssen ein solches Verhalten programmieren, zum Beispiel:

using (var ctx = new MyContext()) 
{ 
    var officialToDelete = ctx.Officials.Single(o => o.OfficialID == 5); 
    var tournaments = ctx.Tournaments.Where(t => t.OfficialID == 5).ToList(); 

    foreach (var tournament in tournaments) 
     tournament.OfficialID = null; 

    ctx.Officials.Remove(officialToDelete); 

    ctx.SaveChanges(); 
} 

Ich glaube, dass die foreach Schleife nicht notwendig ist, da EF die Beziehungen fixup wird (= setzen Sie den Fremdschlüssel auf null), wenn Sie Remove nennen. (Grundsätzlich führt EF selbst diese Schleife intern durch.) Wichtig ist jedoch, dass die Turniere in den Kontext geladen werden, da EF diese Beziehungsfixierung (nur für angefügte (= geladene) Entitäten), nicht die Datenbank (im Gegensatz zum kaskadierenden Löschen) berücksichtigt).

+0

Sie haben Recht. Als ich versuchte, es in der SMSS zu löschen, gab es natürlich keine Möglichkeit für die EF, das für mich zu lösen. Sobald ich es im Code getestet habe, funktionierte es, ohne die foreach-Schleife hinzufügen zu müssen. Vielen Dank nochmal. – Mekswoll

+0

@pEkvo: BTW: Wenn es ohne die foreach-Schleife funktioniert, dann kannst du die "Turniere" -Variable wegwerfen und den Code etwas vereinfachen: 'ctx.Tournaments.Where (t => t.OfficialID == 5) .Load () '. Es lädt nur die Objekte in den Kontext, ohne die Objekte zu einer Listenvariablen zurückzugeben. – Slauma