3

データベースに監査テーブルがあり、更新時に古い値と新しい値が XML にシリアル化され、同じ行に格納されます。オブジェクトは現在、次のようにディープ クローンされています。

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

これは機能しますが、ディープ クローンから引き出された関連レコードが原因で膨大な量のデータが生成され、DB から数十万回の読み取りが行われdcSer.WriteObject(memoryStream, obj)、最終的な MemoryStream サイズは約 200MB になり、書き込まれるデータの量は言うまでもありません。 DBに戻ります。理想的ではありません。

したがって、代わりにメンバーごとのクローンを作成したいと思います。メンバーごとのクローンはオブジェクト参照を除外し、関連するすべての Entity Framework モデルをコピーしないようにすることを理解しています。

だから私はこれをしました:

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

EntityObjectしかし、着信の実際のタイプはテーブル自体に関連するサブクラスであるため、無効なキャスト例外が発生します。

また、拡張メソッドを使用して にアクセスしようとしましたMemberwiseClone()が、拡張メソッドは保護されたメソッドにアクセスできません。

では、ジェネリック EntityObject の浅いコピーを作成するにはどうすればよいでしょうか?

4

3 に答える 3

3

私の最初の推奨事項は、これを試すことです。これは、現在行っていることと似ていますが、オーバーヘッドがほとんどなく、うまくいきました。

DataContractSerializationUtils.SerializeToXmlString(Entity, throwExceptions);

また、以前にこの方法を使用して成功したことがあり、出力が冗長すぎるとは思いません。現在行っていることとほぼ同じようです。

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

これらのオプションのどちらも魅力的ではない場合、リフレクションを使用してソース エンティティからプロパティをコピーする短い関数を作成することをお勧めします。

于 2012-03-14T03:30:50.070 に答える
2

から:

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

シリアル化よりもはるかに効率的で高速です-まさにあなたが探しているものです! 基本的に、リフレクションを使用して必要なプロパティを同じ型の新しい EntityObject にコピーし、ジェネリックを使用して EntityObject から派生した任意のクラスでこれを行うことができます。

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

たとえば、Navigation Property: Orders を持つエンティティ Customer があるとします。次に、上記の方法を次のように使用して、顧客とその注文をコピーできます。

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

foreach(Order order in myCustomer.Orders)
{
    Order newOrder = CopyEntity(myObjectContext, order, true);
    newCustomer.Orders.Add(newOrder);
}
于 2012-10-11T00:23:46.487 に答える