سؤال

لدينا جدول تدقيق في قاعدة بياناتنا، وعند التحديث يتم إجراء تسلسل للقيم القديمة والجديدة إلى 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;
}

أثناء عمل ذلك، فإنه يولد كميات هائلة من البيانات بسبب السجلات ذات الصلة المأخوذة من الاستنساخ العميق، مع مئات الآلاف من القراءات من قاعدة البيانات على dcSer.WriteObject(memoryStream, obj), ، وحجم MemoryStream النهائي يبلغ حوالي 200 ميجابايت، ناهيك عن كمية البيانات التي تتم كتابتها مرة أخرى إلى قاعدة البيانات.ليست مثالية.

لذا أود إجراء استنساخ حسب الأعضاء بدلاً من ذلك، كما أفهم أن استنساخ الأعضاء سيترك مراجع الكائنات خارجًا، ويتجنب نسخ جميع نماذج 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 العام؟

هل كانت مفيدة؟

المحلول

توصيتي الأولى هي تجربة هذا، وهو مشابه لما تفعله الآن، ولكنه نجح معي مع القليل جدًا من النفقات العامة:

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

إذا لم يكن أي من هذه الخيارات يبدو جذابًا، فإن توصيتي هي كتابة دالة قصيرة تستخدم الانعكاس لنسخ أي خصائص من الكيان المصدر.

نصائح أخرى

من:

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

على سبيل المثال لنفترض أن لديك كيانًا:العميل، الذي لديه خاصية التنقل:طلبات.يمكنك بعد ذلك نسخ العميل وطلباته باستخدام الطريقة المذكورة أعلاه كما يلي:

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

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

ماذا عن CurrentValues.ToObject() في EF 6؟

var shallowCopy = (TEntity)_dbContext.Entry(entity).CurrentValues.ToObject();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top