Domanda

Abbiamo una tabella di audit nel nostro database e su Aggiornamento I vecchi e nuovi valori sono serializzati in XML e memorizzati nella stessa riga. Gli oggetti sono attualmente clonati in profondità così:

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;
}
.

Mentre funziona, genera una grande quantità di dati a causa dei record correlati tirati dal clone profondo, con centinaia di migliaia di letture dal DB su dcSer.WriteObject(memoryStream, obj) e un'eventuale dimensione di memorystream di circa 200 MB, per non parlare dell'importo di dati che sono stati registrati sul DB. Non ideale.

Così vorrei invece fare un clone memberwise, in quanto è la mia comprensione che un clone memberwise lascerebbe fuori i riferimenti dell'oggetto ed evitare di copiare tutti i modelli di framework di entità correlati.

Allora ho fatto questo:

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();
    }
}
.

Ma ottengo un'eccezione di fusione non valida perché il tipo effettivo del generatore in entrata è una sottoclasse relativa alla tabella stessa.

Ho anche provato a utilizzare un metodo di estensione per accedere a EntityObject, ma i metodi di estensione non possono accedere ai metodi protetti.

Allora, come posso creare una copia poco profonda di un'entità generica?

È stato utile?

Soluzione

La mia prima raccomandazione sarebbe provare questo, che è simile a ciò che stai facendo ora, ma ha funzionato per me con pochissimo sopraelevato:

DataContractSerializationUtils.SerializeToXmlString(Entity, throwExceptions);
.

Inoltre, ho usato questo metodo prima con il successo, e non trovare anche l'uscita Verbose.Sembra essere quasi identico a quello che stai facendo ora.

    /// <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);
        }
    }
.

Se nessuna delle due opzioni sembra attraente, la mia raccomandazione è scrivere una breve funzione che utilizza la riflessione per copiare qualsiasi proprietà dall'entità sorgente.

Altri suggerimenti

Da:

http://www.codeproject.COM / SUGGERIMENTI / 474296 / CLONE-AN-ENTITY-IN-ENTITY-Framework-4 .

È molto più efficace e più velocemente la serializzazione - solo quello che stai cercando!Fondamentalmente utilizza la riflessione per copiare le proprietà Neccessary in una nuova entityObject dello stesso tipo ed è in grado di farlo su qualsiasi classe derivata da un entityObject facendo uso dei generici.

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;
}
.

Ad esempio dire che hai avuto un'entità: cliente, che ha avuto la proprietà di navigazione: ordini.Puoi quindi copiare il cliente e i loro ordini usando il metodo sopra come:

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

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

Che mi dici di correnteValues.toObject () in EF 6?

var shallowCopy = (TEntity)_dbContext.Entry(entity).CurrentValues.ToObject();
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top