it-swarm.com.de

Zeile aktualisieren, falls vorhanden, Einfügen einer Logik mit Entity Framework

Hat jemand Vorschläge für die effizienteste Art der Implementierung der "Update-Zeile, wenn es sonst Einfügung gibt" mit Entity Framework?

146
Jonathan Wood

Wenn Sie mit einem angehängten Objekt arbeiten (Objekt, das von derselben Instanz des Kontextes geladen wird), können Sie einfach Folgendes verwenden

if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
    context.MyEntities.AddObject(myEntity);
}

// Attached object tracks modifications automatically

context.SaveChanges();

Wenn Sie Wissen über den Schlüssel des Objekts verwenden können, können Sie Folgendes verwenden:

if (myEntity.Id != 0)
{
    context.MyEntities.Attach(myEntity);
    context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
    context.MyEntities.AddObject(myEntity);
}

context.SaveChanges();

Wenn Sie nicht entscheiden können, ob das Objekt anhand seiner ID vorhanden ist, müssen Sie die Abfrage abfragen:

var id = myEntity.Id;
if (context.MyEntities.Any(e => e.Id == id))
{
    context.MyEntities.Attach(myEntity);
    context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
    context.MyEntities.AddObject(myEntity);
}

context.SaveChanges();
147
Ladislav Mrnka

Ab Entity Framework 4.3 gibt es im Namespace System.Data.Entity.Migrations eine AddOrUpdate-Methode:

public static void AddOrUpdate<TEntity>(
    this IDbSet<TEntity> set,
    params TEntity[] entities
)
where TEntity : class

welche durch die doc :

Fügt Entitäten nach Schlüssel hinzu, wenn SaveChanges aufgerufen wird. Äquivalent zu einer "Upert" -Operation von der Datenbank-Terminologie. Diese Methode kann .__ sein. nützlich beim Seeding von Daten mit Migrationen.


Um den Kommentar von @ Smashing1978 zu beantworten, werde ich relevante Teile aus dem von @Colin bereitgestellten Link einfügen

Die Aufgabe von AddOrUpdate ist es sicherzustellen, dass Sie keine Duplikate erstellen wenn Sie Daten während der Entwicklung säen.

Zuerst führt es eine Abfrage in Ihrer Datenbank aus und sucht nach einem Datensatz Was auch immer Sie als Schlüssel (erster Parameter) angegeben haben, stimmt mit dem .__ überein. Zugeordneter Spaltenwert (oder Werte), die im AddOrUpdate bereitgestellt werden. Also das ist ein wenig locker-goosey für das Zusammenbringen aber vollkommen für das Säen Entwurfszeitdaten.

Noch wichtiger ist, wenn eine Übereinstimmung gefunden wird, aktualisiert das Update alle und löschen Sie alle, die sich nicht in Ihrem AddOrUpdate befanden.

Das heißt, ich habe eine Situation, in der ich Daten von einem externen Dienst abrufe und vorhandene Werte per Primärschlüssel einfügte oder aktualisiere (und meine lokalen Daten für Verbraucher schreibgeschützt sind). Ich habe AddOrUpdate bereits seit mehr als 6 Monaten in der Produktion verwendet bisher keine probleme. 

29
Erki M.

Wenn Sie wissen, dass Sie denselben Kontext verwenden und keine Entitäten trennen, können Sie eine generische Version wie folgt erstellen:

public void InsertOrUpdate<T>(T entity, DbContext db) where T : class
{
    if (db.Entry(entity).State == EntityState.Detached)
        db.Set<T>().Add(entity);

    // If an immediate save is needed, can be slow though
    // if iterating through many entities:
    db.SaveChanges(); 
}

db kann natürlich ein Klassenfeld sein oder die Methode kann statisch und als Erweiterung erstellt werden. Dies ist jedoch die Grundlagen.

7
ciscoheat

Die Magie geschieht beim Aufruf von SaveChanges() und hängt von der aktuellen EntityState ab. Wenn die Entität über einen EntityState.Added verfügt, wird sie der Datenbank hinzugefügt. Wenn sie über einen EntityState.Modified verfügt, wird sie in der Datenbank aktualisiert. So können Sie eine InsertOrUpdate()-Methode wie folgt implementieren:

public void InsertOrUpdate(Blog blog) 
{ 
    using (var context = new BloggingContext()) 
    { 
        context.Entry(blog).State = blog.BlogId == 0 ? 
                                   EntityState.Added : 
                                   EntityState.Modified; 

        context.SaveChanges(); 
    } 
}

Mehr zum EntityState

Wenn Sie nicht auf Id = 0 prüfen können, ob es sich um eine neue Entität handelt oder nicht, überprüfen Sie das Antwort von Ladislav Mrnka .

5
Stacked

Ladislavs Antwort war knapp, aber ich musste einige Änderungen vornehmen, damit dies in EF6 (Datenbank zuerst) funktioniert. Ich habe meinen Datenkontext mit meiner on AddOrUpdate-Methode erweitert, und bis jetzt scheint das mit freistehenden Objekten gut zu funktionieren:

using System.Data.Entity;

[....]

public partial class MyDBEntities {

  public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) {
      if (ID != 0) {
          set.Attach(obj);
          ctx.Entry(obj).State = EntityState.Modified;
      }
      else {
          set.Add(obj);
      }
  }
[....]
4
cdonner

Fügen Sie ein anderes Update ein 

public void InsertUpdateData()
{
//Here TestEntities is the class which is given from "Save entity connection setting in web.config"
TestEntities context = new TestEntities();

var query = from data in context.Employee
            orderby data.name
            select data;

foreach (Employee details in query)
{
    if (details.id == 1)
    {
        //Assign the new values to name whose id is 1
        details.name = "Sanjay";
        details. Surname="Desai";
        details.address=" Desiwadi";
    }
    else if(query==null)
    {
        details.name="Sharad";
        details.surname=" Chougale ";
        details.address=" Gargoti";
    }
}

//Save the changes back to database.
context.SaveChanges();
}
2
Sharad Chougale

Meiner Meinung nach ist es wichtig zu erwähnen, dass Sie sich mit dem neu veröffentlichten EntityGraphOperations for Entity Framework Code First ersparen können, einige sich wiederholende Codes zum Definieren der Zustände aller Entitäten im Diagramm zu schreiben. Ich bin der Autor dieses Produkts. Und ich habe es im github , code-project veröffentlicht ( enthält eine schrittweise Demonstration und ein Beispielprojekt steht zum Herunterladen bereit) und Nuget .

Es setzt automatisch den Status der Entitäten auf Added oder Modified. Und Sie müssen manuell auswählen, welche Entitäten gelöscht werden sollen, wenn sie nicht mehr existieren.

Das Beispiel:

Nehmen wir an, ich habe ein Person -Objekt. Person könnte viele Telefone haben, ein Dokument und könnte einen Ehepartner haben.

public class Person
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public string MiddleName { get; set; }
     public int Age { get; set; }
     public int DocumentId {get; set;}

     public virtual ICollection<Phone> Phones { get; set; }
     public virtual Document Document { get; set; }
     public virtual PersonSpouse PersonSpouse { get; set; }
}

Ich möchte den Status aller Entitäten bestimmen, die in der Grafik enthalten sind.

context.InsertOrUpdateGraph(person)
       .After(entity =>
       {
            // Delete missing phones.
            entity.HasCollection(p => p.Phones)
               .DeleteMissingEntities();

            // Delete if spouse is not exist anymore.
            entity.HasNavigationalProperty(m => m.PersonSpouse)
                  .DeleteIfNull();
       });

Wie Sie wissen, können eindeutige Schlüsseleigenschaften beim Definieren des Status der Telefonentität eine Rolle spielen. Für solche speziellen Zwecke haben wir die Klasse ExtendedEntityTypeConfiguration<>, Die von EntityTypeConfiguration<> Erbt. Wenn wir solche speziellen Konfigurationen verwenden möchten, müssen wir unsere Zuordnungsklassen von ExtendedEntityTypeConfiguration<> Und nicht von EntityTypeConfiguration<> Erben. Zum Beispiel:

public class PhoneMap: ExtendedEntityTypeConfiguration<Phone>
    {
        public PhoneMap()
        {
             // Primary Key
             this.HasKey(m => m.Id);
              …
             // Unique keys
             this.HasUniqueKey(m => new { m.Prefix, m.Digits });
        }
    }

Das ist alles.

2
Farhad Jabiyev

Alternative für die Antwort von @LadislavMrnka. Dies gilt für Entity Framework 6.2.0.

Wenn Sie ein bestimmtes DbSet und ein Element haben, das entweder aktualisiert oder erstellt werden muss:

var name = getNameFromService();

var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo);
if (current == null)
{
    _dbContext.Names.Add(name);
}
else
{
    _dbContext.Entry(current).CurrentValues.SetValues(name);
}
_dbContext.SaveChanges();

Dies kann jedoch auch für generische DbSet mit einem einzelnen Primärschlüssel oder einem zusammengesetzten Primärschlüssel verwendet werden.

var allNames = NameApiService.GetAllNames();
GenericAddOrUpdate(allNames, "BusinessSystemId", "NameNo");

public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class
{
    foreach (var value in values)
    {
        try
        {
            var keyList = new List<object>();

            //Get key values from T entity based on keyValues property
            foreach (var keyValue in keyValues)
            {
                var propertyInfo = value.GetType().GetProperty(keyValue);
                var propertyValue = propertyInfo.GetValue(value);
                keyList.Add(propertyValue);
            }

            GenericAddOrUpdateDbSet(keyList, value);
            //Only use this when debugging to catch save exceptions
            //_dbContext.SaveChanges();
        }
        catch
        {
            throw;
        }
    }
    _dbContext.SaveChanges();
}

public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class
{
    //Get a DbSet of T type
    var someDbSet = Set(typeof(T));

    //Check if any value exists with the key values
    var current = someDbSet.Find(keyList.ToArray());
    if (current == null)
    {
        someDbSet.Add(value);
    }
    else
    {
        Entry(current).CurrentValues.SetValues(value);
    }
}
0
Ogglas

Überprüfen Sie die vorhandene Zeile mit Beliebig.

    public static void insertOrUpdateCustomer(Customer customer)
    {
        using (var db = getDb())
        {

            db.Entry(customer).State = !db.Customer.Any(f => f.CustomerId == customer.CustomerId) ? EntityState.Added : EntityState.Modified;
            db.SaveChanges();

        }

    }
0
Ali Osman Yavuz