2012-07-26 8 views
14

ich Probleme, bin mit Änderungen einer Navigationseigenschaft Erkennung:Entity Framework wird keine Änderungen der Navigationseigenschaften erkennen

Mein Testmodell sieht wie folgt aus:

public class Person 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public virtual Address Address { get; set; } 
} 

public class Address 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 
} 

habe ich erstellt und gespeichert ein Objekt vom Typ Person, dem sowohl Name als auch Adresse zugewiesen sind. Mein Problem ist, dass, wenn ich das Person-Objekt von der Datenbank zurückgeholt habe und ich die Address-Eigenschaft ändere (z. B. nach Null), dann die e.f. erkennt die Änderung nicht! Mein Code ist dies:

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.First(); 
    //p.Address IS NOT NULL! 
    p.Address = null; 
    var entry = ctx.Entry(p); 
} 

Warum ist entry.StateUnverändert?

Bearbeiten: Wenn ich die SaveChanges aufrufen, wird der Datensatz korrekt gespeichert (die Adresse wird null)!

Bearbeiten 2: Ich habe die Fremdschlüssel-Eigenschaft als Billy vorgeschlagen und wenn ich das Person-Objekt im Visual Studio inspizieren der Staat ist Modifiziert .. Wenn ich nicht mit dem Debugger die Werte des Objekts zu überprüfen stoppen Zustand ist unverändert!

Bearbeiten 3: Laden des Person-Objekts mit ctx.People.Include (x => x.Address) .First(); löst das Problem. Gibt es eine Möglichkeit, den Aufruf von Include zu vermeiden und die Address-Eigenschaft anstelle von AddressId weiterhin zu ändern?

+0

Was passiert, wenn Sie ctx.DetectChanges() aufrufen? – Maarten

+0

Nichts. Das Ergebnis ist das gleiche !! – Mones

Antwort

24

zu allererst: Sie müssen folgen @ billy Rat Include zu verwenden. Ihre Bemerkung "p.Adresse IST NICHT NULL!" ist nur wahr, weil Sie p.Address im Debugger beobachten und dadurch das verzögerte Laden im Debugger auslösen, so dass die Änderung der Einstellung der Adresse auf null erkannt wird. Im Freigabemodus oder wenn Sie die Eigenschaften im Debugger nicht überprüfen, würde Ihr Code nicht funktionieren und keine Änderungen gespeichert werden.

Also, die Antwort auf Ihren bearbeiten 3: Nein

Zweitens: var entry = ctx.Entry(p) nur zurück Unternehmen besagt und Sie nicht eine Entität Zustand ändern, sondern ein Beziehung Zustand, oder Sie genauer gelöscht eine Beziehung.Sie können keine Beziehung Staaten mit den DbContext API inspizieren, sondern nur mit dem ObjectContext API:

Person p = ctx.People.Include(x => x.Address).First(); 
p.Address = null; 
var objCtx = ((IObjectContextAdapter)ctx).ObjectContext; 
var objentr = objCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted); 

objentr einen Eintrag vom Typ RelationshipEntry jetzt haben:

enter image description here

EF wird diese Beziehung Eintrag betrachten Wenn Sie SaveChanges() aufrufen und die Beziehung löschen, dh die Address Fremdschlüsselspalte der Person in der Datenbank aufsetzen.

Über Bearbeiten 2: Ändern einer Fremdschlüsseleigenschaft (die eine Skalareigenschaft in Ihrem Modell ist) ist eine Änderung der Entität selbst, so dass der Entitätsstatus in diesem Fall Modified ist.

+0

Wow! Danke wirklich gute Antwort! –

+0

Schöne Antwort, aber ich habe Zweifel. Wie erkenne ich, dass ein bestimmter Eintrag diese Änderungen erleidet und nicht andere, weil dies eine Abfrage für den spezifischen Kontext ist? –

+0

Wie machst du das in EF Core, weil es keinen 'ObjectContext' gibt? – grokky

5

Sie müssen das Adressnav einschließen. Stütze. in Ihrer Anfrage, sonst wird EF keine Änderungen daran berücksichtigen, wenn Sie sparen:

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.Include(x => x.Address).First(); 
    //p.Address IS NOT NULL! 
    p.Address = null; 
    var entry = ctx.Entry(p); 
} 

Sie auch Fremdschlüssel in Ihrem Modell verwenden könnte, die ich sehr mag:

public class Person 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public virtual Address Address { get; set; } 

    public int? AddressId {get; set;} 
} 

...

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.First(); 
    p.AddressId = null; 
    var entry = ctx.Entry(p); 
} 
+0

Ich habe die Lösung mit DetectChanges getestet aber keine Möglichkeit .. hat immer noch den Status Unverändert! Wenn ich den Int benutze? Fremdschlüssel Ich denke, es wird richtig funktionieren, weil ich den Wert einer "einfachen" Eigenschaft und nicht der Navigationseigenschaft direkt ändern werde. Wenn ich die Name-Eigenschaft des Person-Objekts ändere, ist alles in Ordnung! – Mones

2

In meiner Anwendung, bevor ein Neuladen angefordert wird oder der Benutzer das Element/die Ansicht verlässt, führe ich einige Überprüfungen durch, um sicherzustellen, dass es keine ungesicherten Änderungen gibt.

Dies ist im Grunde laufen die derzeit angenommene Antwort, aber ich wollte eine Implementierung bereitstellen und darauf aufmerksam machen, dass Sie Context.ChangeTracker.DetectChanges() anrufen müssen, bevor dieBeziehungsänderungen aufnehmen können! Ich habe ziemlich viel Zeit damit verbracht, das zu debuggen, albern!

_EagleContext.ChangeTracker.DetectChanges(); 

var objectContext = ((IObjectContextAdapter)_EagleContext).ObjectContext; 
var changedEntities = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified); 

if (_EagleContext.ChangeTracker.Entries().Any(e => e.State == EntityState.Modified) 
    || changedEntities.Count() != 0) 
{ 
    var dialogResult = MessageBox.Show("There are changes to save, are you sure you want to reload?", "Warning", MessageBoxButton.YesNo); 
    if (dialogResult == MessageBoxResult.No) 
    { 
     return; 
    } 
} 

// Continue with reloading... 
Verwandte Themen