2017-07-02 5 views
0

Ich bin ein Problem mit Einfügen oder Aktualisieren von etwa 950 Entitäten.Entity Framework Core1.1 - Bulk-Insert oder Update - InvalidOperationException

var coins = JsonConvert.DeserializeObject<List<Currency>>(json); 
var sw = new Stopwatch(); 
sw.Start(); 
using (var ctx = CryptoContext.Get) 
{ 
    var existingCoins = ctx.Coins.ToList(); 
    foreach (var coin in coins) 
    { 
     var existing = existingCoins.FirstOrDefault(c => c.CMC_Id == coin.CMC_Id); 
     if (existing != null) 
     { 
      ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Modified; 
     } else 
     { 
      ctx.Entry<Currency>(coin).State = Microsoft.EntityFrameworkCore.EntityState.Added; 
     } 

    } 
    ctx.SaveChanges(); 
    var el = sw.ElapsedMilliseconds; 
} 

Der Code läuft im Hintergrund meines netcoreapp1.1, mit SQLite und ruft eine Liste der Währungen. Dies geschieht alle 5 Minuten mit FluentScheduler. Da es sich nicht um große Objekte handelt, führe ich alle Vergleiche im Speicher durch und versuche, jeden einzelnen hinzuzufügen oder zu aktualisieren. Meine Entität hat eine von der Datenbank angegebene Id-ID, und die API, von der ich abrufe, garantiert, dass CMC_Id eindeutig ist.

Die anfängliche Einfügung funktioniert einwandfrei. Ich bekomme einen Fehler beim zweiten "Update". Ich glaube, was passiert ist, dass ich mehrere Entitäten bin Tracking als modifiziert, dass jeweils eine Id von 0

Ich habe versucht, diesen zu folgen: https://msdn.microsoft.com/en-us/library/jj592676(v=vs.113).aspx

und der Fehler I erhalten: "The instance of entity type 'Currency' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context."

I Ich bin nicht sicher, wie ich mit der Aktualisierung jeder Zeile fortfahren soll.

+0

ich Bandaided haben dieses Problem, indem sie einfach alle Münzen zu entfernen und dann erneut hinzufügen sie, Markierung, wenn der geimpften Id zu hoch ist und es zurückgesetzt wird. Der Vorgang dauert ungefähr 7 Sekunden. –

Antwort

0

Problem hier mehrere Entitäten mit dem gleichen Schlüssel gefragt werden verfolgt werden.

Wenn Sie EntityEntry.State auf etwas setzen, beginnt EF Core mit der Verfolgung der Entität in dem bestimmten Status. Da in Ihrem Code die Datenbank abgefragt wird, um die vorhandene Entität zu ermitteln, beginnt EF Core, die Entität mit dem angegebenen Schlüssel zu verfolgen. Daher wird bei der Einstellung EntityEntry.State die obige Ausnahme ausgelöst, da bereits Entität mit demselben Schlüssel verfolgt wird.

Genauer gesagt versuchen Sie AddOrUpdate. Es gibt mehrere Möglichkeiten, das Verhalten zu erreichen. Welche davon am besten ist, hängt davon ab, ob Sie eine Entität ohne Relation oder eine komplexe Grafik hinzufügen.

Die einfachste Methode wäre, nur die Existenz zu überprüfen, anstatt die Entität aus der Datenbank zu verfolgen. Die Option dafür wäre, in Ihrer Abfrage AsNoTracking zu verwenden, damit EF das Tracking nicht startet. Noch optimierter wäre es, nur aus der Datenbank zu zählen. Wenn Sie eine PK-Eigenschaft abfragen, wird die Anzahl entweder 0 (nicht vorhanden) oder 1 (vorhandene Entität) sein. Wenn es nicht existiert, rufen Sie Add an, ansonsten Update.

var updatedBlog = new Blog { Id = 1, Title = "Updated" }; 
var exist = db.Blogs.Count(b => b.Id == updatedBlog.Id) != 0; 
if (exist) 
{ 
    db.Update(updatedBlog); 
} 
else 
{ 
    db.Add(updatedBlog); 
} 
db.SaveChanges(); 

Seit Add oder Update Methoden starten ganze Graph-Tracking, wenn Ihr Diagramm in einem konsistenten Zustand ist, (alle Einheiten sind neu oder alle geändert werden), dann wäre es gut funktionieren.

Wenn Ihr Diagramm etwas inkonsistent ist, kann der Status jedes Knotens im Diagramm unterschiedlich sein (z. B. Aktualisieren eines Blogs, aber neue Beiträge). Dann sollten Sie EntityEntry.State für einzelne Entität verwenden. Dadurch wird sichergestellt, dass der Status nur auf eine gegebene Entität und keine andere zugehörige Entität in der Grafik angewendet wird. Obwohl Sie für jeden Knoten in der Grafik eine Überprüfung durchführen müssen. Eine weitere Alternative besteht darin, die Methode Attach zu verwenden, um den gesamten Graphen im Unchanged-Status anzuhängen und dann den Status für den einzelnen Knoten festzulegen.

Wenn Sie automatisch generierte Schlüsselwerte haben, haben Sie wahrscheinlich nur dann einen PK-Wert, der aktualisiert wird, sonst wäre es CLR-Standard. Bei einer einzelnen Entität ohne Beziehungen können Sie diese Überprüfung selbst vornehmen, anstatt die Datenbank wie oben beschrieben abzufragen und eine Entscheidung zu treffen.Für Diagramme können Sie verwenden

db.ChangeTracker.TrackGraph(updatedBlog, n => n.Entry.State = n.Entry.IsKeySet ? EntityState.Modified : EntityState.Added); 

Dies setzt den Status jedes Knotens basierend auf PK-Wert festgelegt oder nicht festgelegt.

this helps :)

Verwandte Themen