2013-03-26 4 views
12

Ich versuche ein Objekt mit EntityFramework 5 zu löschen, aber ich erhalte diesen Fehler. Das Objekt kann nicht gelöscht werden, da sie nicht in der Object
gefunden wurde ich bin mit der Remove() Methode als DeleteObject() in EF5 nicht vorhanden ist. Kann mir jemand helfen, was fehlt mir?Das Objekt kann nicht gelöscht werden, weil es nicht im ObjectStateManager im Entitätsframework gefunden wurde. 5

funktioniert das nicht für Remove

localDb.Customers.Remove(new Customer() { CustomerId = id }); 
       localDb.SaveChanges(); 

Eine andere Sache, die ich von Msdn versucht, den Staat zu Deleted zu ändern. Aber hier gibt es einen Fehler, der besagt, dass alle Felder vorhanden sein sollten. Ist es notwendig, den kompletten Datensatz zu löschen und dann zu löschen?

var customer = new Customer(){ CustomerId = id }; 
       localDb.Customers.Attach(customer); 

       localDb.Entry(customer).State = EntityState.Deleted; 
       localDb.SaveChanges(); 

Irgendwelche Eingaben?

Antwort

24

Sie können die Zeile aus der Datenbank abrufen und dann löschen, aber dies verursacht 2 Rundreisen zur Datenbank.

Wenn Sie es in einem Treffer tun möchten, wird Ihre zweite Version mit Attach funktionieren - solange die Entität nicht bereits in den Kontext geladen ist.

Der Fehler, den Sie erhalten, wird durch die EF-Validierung verursacht, die vor dem Schreiben einer Datenbank ausgeführt wird.

Sie können es vorübergehend wie folgt deaktivieren:

bool oldValidateOnSaveEnabled = localDb.Configuration.ValidateOnSaveEnabled; 

try 
{ 
    localDb.Configuration.ValidateOnSaveEnabled = false; 

    var customer = new Customer { CustomerId = id }; 

    localDb.Customers.Attach(customer); 
    localDb.Entry(customer).State = EntityState.Deleted; 
    localDb.SaveChanges(); 
} 
finally 
{ 
    localDb.Configuration.ValidateOnSaveEnabled = oldValidateOnSaveEnabled; 
} 
+0

Danke Nicholas, nur um mein Konzept zu verbessern. Warum wird die Validierung auf der EF-Seite statt auf der SQL-Seite durchgeführt? ist dies der einzige Weg für einen einzigen Treffer, weil diese Einstellungen mir wichtig erscheinen ... Bitte korrigieren Sie mich, wenn etwas nicht stimmt. –

+0

Bis jetzt ist dies die einzige Antwort, die ich glaube, ohne 2 Trips nach Db zu verursachen. Also dies als die Antwort in Bezug auf die Leistung zu markieren. –

+0

northwind.Entry (entity) .State = System.Data.Entity.EntityState.Deleted; für mich behoben, danke – balron

2

Können Sie das einfach tun?

+0

Ja, aber können wir eine Entität nicht nur mit einem Primärschlüssel löschen? Können wir den Primärschlüssel oder etwas in diesen Zeilen setzen? –

+0

Was Sie in Ihrem zweiten Beispiel haben, sollte eigentlich funktionieren, haben Sie versucht, temporäre Standardwerte für die erforderlichen Felder zu setzen und zu löschen? Ihre Werte sollten keine Rolle spielen, da Sie das Objekt sowieso löschen. Der primäre Schlüssel (Entität) muss nur genau sein. –

6

, wenn Sie Objekt aus der Datenbank abgerufen dann ist es bereits auf den Kontext gebunden, so dass Sie durch löschen:

db.myTable.Remove(model); 

aber
Wenn Sie gerade Modell von bearbeiten oder löschen Sie die Ansicht per Post oder generiert es selbst, um 2 Fahrten zur Datenbank zu vermeiden, dann EF nicht darüber wissen, und Sie erhalten Fehler mit der oberen Zeile (.. nicht in der Object gefunden ..), so dass Sie gesetzt seinen Zustand „Gelöscht“ zu EF durch informieren: für mich

//generate it yourself if not posted from edit/delete view 
//var model = new Model { Id = 123 }; 

//set to delete 
db.Entry(model).State = EntityState.Deleted; 
db.SaveChanges(); 
0
public T Delete<T>(T obj) where T : class 
     { 
      T existing = context.Set<T>().Find(GetKeys(obj, context)); 

      if (existing != null) 
      { 
       context.Set<T>().Remove(existing); 
       context.SaveChanges(); 
       return existing; 
      } 
      return null; 
     } 

private object[] GetKeys<T>(T entity, DbContext context) where T : class 
     { 
      ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 
      ObjectSet<T> set = objectContext.CreateObjectSet<T>(); 
      var keyNames = set.EntitySet.ElementType 
                 .KeyMembers 
                 .Select(k => k.Name).ToArray(); 
      Type type = typeof(T); 

      object[] keys = new object[keyNames.Length]; 
      for (int i = 0; i < keyNames.Length; i++) 
      { 
       keys[i] = type.GetProperty(keyNames[i]).GetValue(entity, null); 
      } 
      return keys; 
     } 
0

Ich weiß, diese Frage ist ziemlich alt, aber keiner der oben gearbeitet, seit Ich löschte Register aus mehr als einer Klasse/Service auf einmal und jeder von ihnen war Instanziierung seiner eigenen Datenbankverbindung Kontext.

Was ich getan habe, um es zu lösen, war, den ersten erstellten Kontext an den Rest der Klassen/Dienste zu senden, die auf die Datenbank zugreifen wollten.

Zum Beispiel würde meine serviceA einige seiner Register löschen und serviceB und serviceC anrufen, um das gleiche mit ihren Registern zu tun.

dann würde ich meine Register auf serviceA und übergeben Sie als Parameter die auf der serviceA-serviceB und serviceC erstellt Kontext löschen.