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

虽然这可行,但由于从深度克隆中提取的相关记录,它会生成大量数据,从数据库中读取数十万次,dcSer.WriteObject(memoryStream, obj)最终 MemoryStream 大小约为 200MB,更不用说正在写入的数据量回到数据库。不理想。

所以我想做一个成员克隆,因为我的理解是成员克隆会将对象引用排除在外,并避免复制所有相关的实体框架模型。

所以我这样做了:

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

例如,假设您有一个实体:客户,它具有导航属性:订单。然后,您可以使用上述方法复制客户及其订单,如下所示:

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 回答
0

EF 6 中的 CurrentValues.ToObject() 怎么样?

var shallowCopy = (TEntity)_dbContext.Entry(entity).CurrentValues.ToObject();
于 2018-03-28T14:28:41.253 回答