これが私がEFを使用している状況です。
リポジトリは A のインスタンスを取得し、プレゼンテーション層 (つまり、MVC コントローラー) に戻ります。
コントローラーは、A のインスタンスの特定のプロパティを変更し、与えられたインスタンスを永続化します。
永続化する前に、オブジェクトに対して行われた変更を把握し、変更が許可されているかどうかを検証する必要があります。
変更を比較するには、データベースの古いインスタンスが必要です。
しかし、EF は同じ汚れたインスタンスを返すため、それらを比較することはできません。
私がやってみたこと:クラス構造
public Class A {
public B B {get;set;}
}
public class B {
public ICollection<A> As {get;set;}
public C c { get; set;}
}
public class C {
}
B と C は同じデータベース テーブルにマップされます。
これは、EF が古いインスタンスを追跡しており、そのインスタンスで save がまだ呼び出されていないためです。そのため、同じ inatce が返されます。
そのため、遅延読み込みとプロキシ生成をオフにし、オブジェクトをリポジトリの追跡不可として返しました。
EF は DB から新しいレコードを返しますが、A のプロパティを変更すると、B の A のコレクションで、コレクション全体ではなく、変更した A のインスタンスのみが読み込まれます。
新しい A を作成して保存する場合は、次のようにします
B b = GetSomeOldB(); A a = 新しい A(); aB = b a.Save();
したがって、基本的には新しい A をコンテキストに追加し、SaveChanges を呼び出します。
Ef は、「C を B にキャストできません」という例外を返します。
基本的に、私が望むのは、コンテキストから古いオブジェクト グラフを取得することだけです。
本当に助けていただければ幸いです!!
最終的に実装されたソリューションは次のとおりです。 1. 追跡とプロキシの作成を元に戻します。 2. EF から元のコピーを取得します。3.エンティティの新しいインスタンスをハイドレートするために、この一般的なメソッドを作成しました
public ICollection<T> GetOriginalCollection<T>(ICollection<T> changedCollection) where T : class {
ICollection<T> original = new Collection<T>();
foreach (var item in changedCollection) {
//Dont return the newly added ones to the original collection
if (_context.Entry(item).State != EntityState.Added){
original.Add(GetOriginal(item));
}
}
return original;
}
public T GetOriginal<T>(T changedEntity) where T : class {
Func<DbPropertyValues, Type, object> getOriginal = null;
getOriginal = (originalValues, type) =>
{
object original = Activator.CreateInstance(type, true);
foreach (var ptyName in originalValues.PropertyNames) {
var property = type.GetProperty(ptyName);
object value = originalValues[ptyName];
//nested complex object
if (value is DbPropertyValues) {
property.SetValue(original, getOriginal(value as DbPropertyValues, property.PropertyType));
} else{
property.SetValue(original, value);
}
}
return original;
};
return (T)getOriginal(_context.Entry(changedEntity).OriginalValues, typeof(T));
}