コメントで述べたように、反射コードは問題ではありませんが、(例外メッセージが明示的に示すように) エンティティ参照の 1 つのリセットを間接的にトリガーしているという事実です。私のアドバイスは2つあります。リフレクションコードを変更して、スカラープロパティ(文字列、日付など)のみをコピーするか、参照とコレクションを無視するか、シリアル化を使用します。
public static T CloneBySerialization<T>(this T source) where T : EntityObject {
var serializer = new DataContractSerializer(typeof(T));
using (var ios = new MemoryStream()) {
serializer.WriteObject(ios, source);
ios.Seek(0, SeekOrigin.Begin);
return ((T) serializer.ReadObject(ios));
}
}
このアプローチでは、完全なオブジェクト グラフまたは参照になってしまうことに注意してください。複製されたオブジェクトがエンティティである場合、参照と外部キーも「逐語的に」コピーされているため、それを使用したり別のコンテキストにアタッチしたりすることはできず、これはすべて競合につながる可能性があります。キーでID列を使用している場合、問題はさらに悪化します。
私はこれらの問題に関して以前の仕事で多くの魔法を使いました。クローンに関する限り、必要なのは上記のコードだけです。すべて、本当に。
ただし、コンテキストの問題と複製されたエンティティの使いやすさを修正するには、参照をクリアし、¹ ↔ * 方向リレーショナル グラフの「ルート」エンティティも操作しているという前提の下で行う必要があります (話が長いので少しはっきりしています)以下も必要になります。
public static void ClearReferences(this EntityObject entity) {
if (entity == null)
return;
foreach (var p in entity.GetType().GetProperties()) {
if (p.PropertyType.IsGenericType) {
var propertyType = p.PropertyType.GetGenericTypeDefinition();
if (propertyType == typeof(EntityReference<>)) {
var reference = p.GetValue(entity) as dynamic;
if (reference.EntityKey != null) {
reference.EntityKey = null;
((EntityObject) reference.Value).ClearReferences();
}
}
if (propertyType == typeof(EntityCollection<>)) {
var children = (p.GetValue(entity) as IEnumerable<EntityObject>).ToList(); // covariance
foreach (var child in children)
child.ClearReferences();
}
}
}
}
したがって、最初に(シリアライゼーション/デシリアライゼーションを介して)クローンを作成し、次に「精製」するという考え方です。