Frage

Wir haben eine Prüftabelle in unserer Datenbank und bei der Aktualisierung werden die alten und neuen Werte in XML serialisiert und in derselben Zeile gespeichert.Die Objekte werden derzeit wie folgt tief geklont:

public EntityObject CloneEntity(EntityObject obj)
{
    DataContractSerializer dcSer = new DataContractSerializer(obj.GetType());

    MemoryStream memoryStream = new MemoryStream();

    dcSer.WriteObject(memoryStream, obj);

    memoryStream.Position = 0;

    EntityObject newObject = (EntityObject)dcSer.ReadObject(memoryStream);

    return newObject;
}

Dies funktioniert zwar, erzeugt jedoch aufgrund der zugehörigen Datensätze, die aus dem Deep Clone abgerufen werden, große Datenmengen mit Hunderttausenden Lesevorgängen aus der Datenbank dcSer.WriteObject(memoryStream, obj), und eine letztendliche MemoryStream-Größe von etwa 200 MB, ganz zu schweigen von der Datenmenge, die in die Datenbank zurückgeschrieben wird.Nicht ideal.

Deshalb würde ich stattdessen gerne einen Klon nach Mitgliedern durchführen, da ich davon ausgehe, dass bei einem Klon nach Mitgliedern die Objektreferenzen weggelassen werden und das Kopieren aller zugehörigen Entity Framework-Modelle vermieden wird.

Also habe ich Folgendes gemacht:

public EntityObject CloneEntity(EntityObject obj)
{
    EntityObjectAuditable auditable = (EntityObjectAuditable)obj; // invalid cast exception

    return auditable.ShallowCopy();
}

// ....

public class EntityObjectAuditable : EntityObject
{
    public EntityObjectAuditable ShallowCopy()
    {
        return (EntityObjectAuditable)this.MemberwiseClone();
    }
}

aber ich erhalte eine ungültige Cast-Ausnahme aufgrund des tatsächlichen Typs des eingehenden EntityObject ist eine Unterklasse, die sich auf die Tabelle selbst bezieht.

Ich habe auch versucht, eine Erweiterungsmethode für den Zugriff zu verwenden MemberwiseClone(), aber Erweiterungsmethoden können nicht auf geschützte Methoden zugreifen.

Wie kann ich also eine flache Kopie eines generischen EntityObject erstellen?

War es hilfreich?

Lösung

Meine erste Empfehlung wäre, Folgendes auszuprobieren: Es ähnelt dem, was Sie jetzt tun, hat bei mir aber mit sehr geringem Aufwand funktioniert:

DataContractSerializationUtils.SerializeToXmlString(Entity, throwExceptions);

Außerdem habe ich diese Methode schon einmal mit Erfolg verwendet und finde die Ausgabe nicht zu ausführlich.Es scheint fast identisch mit dem zu sein, was Sie jetzt tun.

    /// <summary>
    /// Creates an exact duplicate of the entity provided
    /// </summary>
    /// <param name="source">The source copy of the entity</param>
    /// <returns>An exact duplicate entity</returns>
    public TEntity Clone(TEntity Source)
    {
        // Don’t serialize a null object, simply return the default for that object
        if (ReferenceEquals(Source, null))
        {
            return default(TEntity);
        }
        var dcs = new DataContractSerializer(typeof (TEntity));
        using (Stream stream = new MemoryStream())
        {
            dcs.WriteObject(stream, Source);
            stream.Seek(0, SeekOrigin.Begin);
            return (TEntity) dcs.ReadObject(stream);
        }
    }

Wenn keine dieser Optionen ansprechend erscheint, empfehle ich, eine kurze Funktion zu schreiben, die Reflektion verwendet, um alle Eigenschaften aus der Quellentität zu kopieren.

Andere Tipps

Aus:

http://www.codeproject.com/Tips/474296/Clone-an-Entity-in-Entity-Framework-4.

Es ist viel effizienter und schneller als die Serialisierung – genau das, was Sie suchen!Grundsätzlich verwendet es Reflektion, um die erforderlichen Eigenschaften in ein neues EntityObject desselben Typs zu kopieren, und ist in der Lage, dies für jede von einem EntityObject abgeleitete Klasse durch Verwendung von Generika zu tun.

public static T CopyEntity<T>(MyContext ctx, T entity, bool copyKeys = false) where T : EntityObject
{
T clone = ctx.CreateObject<T>();
PropertyInfo[] pis = entity.GetType().GetProperties();

foreach (PropertyInfo pi in pis)
{
    EdmScalarPropertyAttribute[] attrs = (EdmScalarPropertyAttribute[])pi.GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false);

    foreach (EdmScalarPropertyAttribute attr in attrs)
    {
        if (!copyKeys && attr.EntityKeyProperty)
            continue;

        pi.SetValue(clone, pi.GetValue(entity, null), null);
    }
}

return clone;
}

Angenommen, Sie hätten eine Entität:Kunde, der die Navigationseigenschaft hatte:Aufträge.Anschließend können Sie den Kunden und seine Bestellungen mit der oben beschriebenen Methode wie folgt kopieren:

Customer newCustomer = CopyEntity(myObjectContext, myCustomer, false);

foreach(Order order in myCustomer.Orders)
{
    Order newOrder = CopyEntity(myObjectContext, order, true);
    newCustomer.Orders.Add(newOrder);
}

Was ist mit CurrentValues.ToObject() in EF 6?

var shallowCopy = (TEntity)_dbContext.Entry(entity).CurrentValues.ToObject();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top