「切断された」コンテキストを使用する場合、EF6 に問題があります。私は最初にデータベースを使用しており、このように多対多の関係をモデル化しています (表示されている関係の背後にジャンクション テーブルがあり、2 つの FK が一緒になってジャンクション テーブルの複合 PK を構成しています。その中に他の列はありません)ジャンクション テーブル):
私は切断された方法で EF を使用したいので (短命のコンテキスト、Web API の準備ができています)、DbContext に関する Julie Lerman と Rowan Millers の本からの「状態の描画」メソッドも実装しました。具体的には、本の第4章「元の値の記録」(p.102以降)で説明されている方法です。これは私の ApplyChanges メソッドです:
public static void ApplyChangesInGraph<TEntity>(TEntity root) where TEntity : class, IObjectWithState
{
using (var context = new NovaEntities2())
{
context.Set<TEntity>().Add(root);
foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.State);
if (stateInfo.State == State.Unchanged)
{
ApplyPropertyChanges(entry.OriginalValues, stateInfo.OriginalValues);
}
}
context.SaveChanges();
}
}
これを行うと、次のテストで例外が発生します。
[Fact]
public void ShouldNotResultInAnInsertOfPlaceOfEmployment()
{
ResetDbToKnownState();
Employee employee;
using (var context = new NovaEntities2())
{
employee = context.Employees
//.Include(e => e.PlacesOfEmployment) // If enabled, an exception is thrown.
.First();
}
employee.Name = "A new name";
NovaEntities2.ApplyChangesInGraph(employee);
}
上記の .Include を有効にすると、次の例外が発生します。
System.Data.Entity.Infrastructure.DbUpdateException関係の外部キー プロパティを公開しないエンティティの保存中にエラーが発生しました。単一のエンティティを例外のソースとして識別できないため、EntityEntries プロパティは null を返します。保存中の例外の処理は、エンティティ タイプで外部キー プロパティを公開することで簡単に行うことができます。詳細については、InnerException を参照してください。
InnerException: PRIMARY KEY 制約 'PK_EmployeePlaceOfEmployment' の System.Data.SqlClient.SqlExceptionViolation。オブジェクト 'dbo.EmployeePlaceOfEmployment' に重複するキーを挿入できません。重複キーの値は (140828, 14) です。すなわち。上記の .Include を追加すると、EF は、従業員の名前のみを更新しようとする上記の単純なケースで、従業員の更新 (問題あり) と既存の PlaceOfEmployment の挿入 (あまり問題ありません) を発行します。
主キーに違反して、ここで INSERT が発生する理由を一生理解できません。ApplyChanges メソッドで foreach をステップ実行してみましたが、すべてのエンティティの状態が正しく設定されていることを確認しました。実際、最初の反復では、Employee エンティティは追加済みとして開始され、最終的に変更済み状態になります。次に、熱心にロードされた PlaceOfEmployment エンティティが処理され、Added として開始され、Unchanged 状態で終了します。ただし、INSERT がまだ生成されているため、例外が発生します。
SQL プロファイラーから: