2009-03-12 13 views
12

LINQ to SQLエンティティを複製してデータベースに新しいレコードを作成する際のベストプラクティスとは何でしょうか?LINQ to SQLのエンティティ/レコードが重複していますか?

コンテキストは、管理者のグリッド内のレコードの複製機能を作成することです。いくつかのことを明らかにして、データを読み込み、ID = 0を変更し、名前を変更し、submitChanges()とし、例外を叩いた。私は止めて専門家に尋ねるかもしれないと思った。

最初にレコードを読み込み、 "Copy Of"という接頭辞を付けて名前を変更してから新しいレコードとして保存したいと考えています。

答えて

11

新しいインスタンスを作成し、リバースと一緒にlinqマッピングクラスを使用してメンバー値をコピーします。

など。

public static void CopyDataMembers(this DataContext dc, 
            object sourceEntity, 
            object targetEntity) 
{ 
    //get entity members 
    IEnumerable<MetaDataMember> dataMembers = 
     from mem in dc.Mapping.GetTable(sourceEntity.GetType()) 
           .RowType.DataMembers 
     where mem.IsAssociation == false 
     select mem; 

    //go through the list of members and compare values 
    foreach (MetaDataMember mem in dataMembers) 
    { 
     object originalValue = mem.StorageAccessor.GetBoxedValue(targetEntity); 
     object newValue = mem.StorageAccessor.GetBoxedValue(sourceEntity); 

     //check if the value has changed 
     if (newValue == null && originalValue != null 
      || newValue != null && !newValue.Equals(originalValue)) 
     { 
      //use reflection to update the target 
      System.Reflection.PropertyInfo propInfo = 
       targetEntity.GetType().GetProperty(mem.Name); 

      propInfo.SetValue(targetEntity, 
           propInfo.GetValue(sourceEntity, null), 
           null); 

      // setboxedvalue bypasses change tracking - otherwise 
      // mem.StorageAccessor.SetBoxedValue(ref targetEntity, newValue); 
      // could be used instead of reflection 
     } 
    } 
} 

...か、DataContractSerializerを使用してクローンを作成することができます

internal static T CloneEntity<T>(T originalEntity) where T : someentitybaseclass 
{ 
    Type entityType = typeof(T); 

    DataContractSerializer ser = 
     new DataContractSerializer(entityType); 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     ser.WriteObject(ms, originalEntity); 
     ms.Position = 0; 
     return (T)ser.ReadObject(ms); 
    } 
} 
+0

は、ルッククリストファーかかります。 – GONeale

+0

すばらしい答え!これは機能している、私は反映を検討した。この解決策についてどう思いますか?私は、同じような操作を行うと期待していた組み込みのClone()を想定しています。 – GONeale

+1

エンティティで読み取り専用のプロパティがある場合は、propInfo.SetValueを呼び出す前にプロパティにセッターがあるかどうかを確認する必要があります。 propInfo.GetSetMethod()がnull以外の値を返すかどうかを調べることができます。 – pbz

3

Iは、多くのおかげで、同じ問題で立ち往生し、クリストファーのコードが完全に働きました!

興味がある場合は、コードを少し変更して、ターゲットエンティティをパラメータとして受け入れる代わりに、新しいオブジェクトを作成して返します。また、私は一般的なことsourceEntityパラメータをした:

public static T CloneEntity<T>(this DataContext dc, T sourceEntity) where T:class, new() 
{ 
    var targetEntity = new T(); 
    //... original method code... 
    return targetEntity; 
} 

その後、私は、次の操作を行うことができます。

dataContext.MyEntities.Attach(dataContext.CloneEntity(theEntity)); 
11

あなたがfalseにObjectTrackingEnabledセットでのDataContextからのエンティティをロードした場合、あなたは、このエンティティを挿入することができます別のDataContext

で新しい
DataContext db1 = new DataContext(); 
DataContext db2 = new DataContext(); 

db2.ObjectTrackingEnabled = false; 

MyEntity entToClone = db2.Single(e => e.Id == id); 

// ... change some data if it is needed 

db1.MyEntities.InsertOnSubmit(entToClone); 
db1.SubmitChanges(); 
+0

ありがとう非常に、これが最適なソリューションです。 – JanBorup

+0

はい、これが最適なソリューションです。ありがとう! – Rudy

+0

私はそれも子オブジェクトを複製していることがわかりました。私はまだこれが最善の解決策だと思っています。 Linq to SQLには、このための洗練されたメソッドが組み込まれている必要があります。 – Rudy

0

ここVB.NetでのLINQからSQLへのEntiryクローンのために、ピーター・K.として、彼と同じソリューションです。エンティティフレームワークで

Dim DC As New DataContext 
    Dim DCI As New DataContext 
    DC.ObjectTrackingEnabled = False 

     Dim RGF As sf_RuleGroup = (From G In DC.sf_RuleGroups _ 
            Where G.RuleGroupID = CInt(e.CommandArgument) _ 
            Select G).First() 
     DCI.sf_RuleGroups.InsertOnSubmit(RGF) 
     DCI.SubmitChanges() 
0

あなたがこれを行うことができます6

Dim WorkoutNew As New Workout 'create a record 
ff7db.Workouts.Add(WorkoutNew) 'add it to the table (workout) 
ff7db.Entry(WorkoutNew).CurrentValues.SetValues(WorkoutsPost) ' update its values with a class with the same properties