EF Exception Inquiry (エンティティオブジェクトは、IEntityChangeTrackerの複数のインスタンスから参照できません。)...
今日、以前の古いプロジェクトを改修しているときに、以前の非標準的なEFの書き方に起因するバグが発生しました。例外メッセージは以下のようなものでした。
" 1 つのエンティティ オブジェクトを IEntityChangeTracker の複数のインスタンスで参照することはできません。 ( エンティティオブジェクトは、IEntityChangeTracker の複数のインスタンスからは参照できません。 )"。
のプログラムなので、実は問題を見つけるのは簡単なのです。
同じエンティティを追跡するために異なるDbContextが使用されています。 .
次のデモコードでは、この例外を簡単に発生させることができます。
using (var dbContext = new ADbContext())
{var aa = dbContext.ClassA.Where(p => p.Id == 1).FirstOrDefault();
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
EntityState.Modified; using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
ただし、ClassA には ナビゲーション属性 を以下のように設定します。
public class ClassA
{
public int Id { get; set; }
public string guid { get; set; }
public int? child_id { get; set; }
[ForeignKey("child_id")]
public virtual ClassB child { get; set; }
}
ほとんどの場合、よく設計されたシステムは Uow (unit of work) を使って、すべてのリクエストが同じ DbContext を使うようにします (MSDTC を必要とするシステムもあるでしょうが、これは対象外です)。任意に新しい DbContext を作成すると例外が発生しやすいだけでなく、適時に解放できないためにメモリの問題が生じることもあります。
上記の例外を修正するのは簡単です。同じDbContextを使用すればいいのです。
しかし、ここで問題が発生します。
このプロジェクトは、以前の実行でなぜエラーが発生しなかったのでしょうか?
エクスペリエンス
上記と同じプロジェクトを使用し、ナビゲーション属性の 仮想 以下のように、削除します。
public class ClassA
classA {
public int Id { get; set; }
public string guid { get; set; }
public int? child_id { get; set; }
[ForeignKey("child_id")]
public ClassB child { get; set; }
}
プロジェクトを実行すると、例外がなくなっていることが確認できます。
具体的にはどのような原因なのでしょうか?
EFについて少し知っている人は、EFのナビゲーションプロパティはデフォルトでディファードローディングがオンになっていることを知っています。
知らない人はキーワードで検索してEFの遅延ロードの基礎知識を追加し、英語が得意な人は公式ドキュメントを閲覧してください( アソシエーションとナビゲーションのプロパティ その 関連するエンティティの読み込み )
virtualが削除されたことで、そのナビゲーションプロパティの遅延ロードがオフになり、そして例外が消えました。
この例外は、遅延読み込みが原因ですか?
また、遅延ロードと IEntityChangeTracker との間にはどのような関係があるのでしょうか?
その理由
IEntityChangeTracker はその名の通り、実際にはエンティティ情報を追跡するために使用されますが、遅延読み込みをオフにした後、両方の DbContexes でエンティティが追跡されていても、エラーが報告されないのは不可解です。
EFのディファードローディングがどのように実装されているかを考えてみましょう。
EFはCastleと同様のダイナミックプロキシ技術を使用していますが、同じ欠点(バーチャルとして識別されないメンバーを傍受できない)があります。
EF のソースコードを見ていないし、公式ドキュメントにも詳しく書かれていないので、IEntityChangeTracker が実際には以下のようなインターセプターと同様の機能を担っているのではないかと推測しています。
DbContext が呼び出されると、エンティティに対する動的プロキシが EF によって生成され、データベースにアクセスするリクエストを傍受し、アクセスされたときにナビゲーションプロパティを入力します。
また、動的プロキシは生成後、他のDbContextにアタッチすることができません。
この推測に基づいて、DbContext の動的プロキシをオフにする次のコードを使用してテストすることができます。
using (var dbContext = new ADbContext())
{
dbContext.Configuration.ProxyCreationEnabled = false;
Where(p => p.Id == 1).FirstOrDefault(). var aa = dbContext.ClassA;
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
EntityState.Modified; using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
合格した結果です。
この例外が実際には遅延ロードとは無関係であることを証明するために、動的プロキシをオンにしてから、遅延ロードをオフにします。
using (var dbContext = new ADbContext())
{
dbContext.Configuration.ProxyCreationEnabled = true;
Configuration.LazyLoadingEnabled = false. dbContext;
Where(p => p.Id == 1).FirstOrDefault(). var aa = dbContext.ClassA;
dbContext.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
EntityState.Modified; using (var db2 = new ADbContext())
{
db2.Entry<ClassA>(aa).State = System.Data.Entity.EntityState.Modified;
dbContext.SaveChanges();
}
dbContext.SaveChanges();
}
それでも例外が発生します。
例外が発生したのは、遅延ロード機能ではなく、EF の動的プロキシされたオブジェクトが単一の DbContext によってのみ追跡可能であることが証明されました。
もう一つ特筆すべき点は
また、EFは、ナビゲーションプロパティがない場合、エンティティの動的プロキシを生成しない。
取得元:https://www.cnblogs.com/RobotZero/p/6496964.html
関連
-
2021MySql-8.0.26インストール詳細チュートリアル(ベビーシッターレベル)
-
Hibernateでhibernate.propertiesが見つからない問題とデータベース方言の更新の問題
-
解決策: テーブルの定義が正しくありません。
-
mongodbの更新操作の更新
-
MongoDBコマンド
-
は、GROUP BY句に含まれるか、集約関数で使用される必要があります。
-
Oracleデータベースの挿入データエラーです。ORA-06550
-
ORA-30926: ソース・テーブルの安定した行のセットを取得できませんか?
-
MySQL上級SQLステートメント
-
AttributeError: 'function' オブジェクトには 'cursor' という属性がありません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
MySQL - エラーです。executeQuery() でデータ操作ステートメントを発行できません。
-
親行が削除または更新できない: 外部キー制約に失敗 解決策
-
(NTDLL.DLL): 0xC0000005: アクセス違反 - 解決
-
unixODBC:データソース名が見つからない、デフォルトドライバが指定されていないに関する質問
-
MySQLデータベースのクエリ機能を使用する際に、グループ関数の使用が無効である問題の解決方法
-
SocketTimeoutExceptionが発生しました。読み取りがタイムアウトした問題のトラブルシューティング
-
SQL SERVER データベース SELECT INTO および INSERT INTO の使用法(テンポラリテーブルへのデータ挿入を含む)
-
01. プロシージャの結果セットを持つ一時テーブルへのSELECT INTO
-
Postgresql でテーブル "t" の FROM 句の項目が見つからない。
-
Linuxでmysql-5.7.30をインストールするための詳細な手順