2012-03-14 42 views
3

的子類的淺拷貝/克隆我們已經在我們的數據庫審計表,並在更新舊的和新的值序列化爲XML並存儲在同一排。對象是目前深克隆這樣的:創建EntityObject

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,更不用說寫回數據庫的數據量。不理想。

所以我想這樣做一個按成員的克隆,而不是,因爲這是我的理解是一個按成員克隆將離開對象引用出來,避免將所有相關的實體框架模型。

所以我這樣做:

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的淺表副本?

+0

我看到有人問前一段時間,但是我有完全相同的問題,並因此增加了,作爲一個解決方案出來了回答任何人想知道! – markmnl 2012-10-11 00:24:55

回答

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

如果這兩個選項看起來很有吸引力,我的建議是寫一個使用反射來的任何屬性從源實體複製一個簡短的函數。

+0

感謝您的回覆。 'DataContractSerializationUtils.SerializeToXmlString'似乎來自西風網絡工具包,我不想將其包含在我的控制檯應用程序中;第二種方法遇到與我目前所做的完全相同的問題;和第三? Urgh。反射。創建一個淺層克隆真的不應該是這麼艱難和脆弱,特別是考慮到'MemberwiseClone'存在。 – sennett 2012-03-14 03:52:59

+0

Blimey我剛剛閱讀我的評論,我碰到了一個沖洗!對於那個很抱歉。非常感謝您的幫助。我最終使用反射,這個答案幫助我從一個類型實例化一個新的實例:http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type-in​​- c-sharp – sennett 2012-03-14 04:11:38

+0

我同意它不應該那麼難。樂意效勞! – msigman 2012-03-14 11:11:46

2

來自:

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

它更efficant和更快然後系列化 - 正是你要找的!基本上它使用反射來將需要的屬性複製到相同類型的新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); 
} 
相關問題