無効なオブジェクトはEFによって完全に忘れられるべきであり、これは自動的に行われると私は信じています。しかし、明らかにそうではありません。
そうではなく、例外が発生したときにエンティティがコンテキストから自動的に切り離されるとは聞いたことがありません。
この問題に対処するには、基本的に2つのオプションがあります。一意キー制約違反の例を含む単純なモデルを示します。
public class Customer
{
// so we need to supply unique keys manually
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name { get; set; }
}
public class MyContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (var ctx = new MyContext())
{
var customer = new Customer { Id = 1, Name = "X" };
ctx.Customers.Add(customer);
ctx.SaveChanges();
}
// Now customer 1 is in database
using (var ctx = new MyContext())
{
var customer = new Customer { Id = 1, Name = "Y" };
ctx.Customers.Add(customer);
try
{
ctx.SaveChanges();
// will throw an exception because customer 1 is already in DB
}
catch (DbUpdateException e)
{
// customer is still attached to context and we only
// need to correct the key of this object
customer.Id = 2;
ctx.SaveChanges();
// no exception
}
}
}
}
上記が推奨される解決策です。コンテキストにアタッチされているオブジェクトを修正します。
何らかの理由で新しいオブジェクトを作成する必要がある場合は、古いオブジェクトをコンテキストから切り離す必要があります。そのオブジェクトはまだ状態Added
にあり、呼び出したときにEFはオブジェクトを再度保存しようとしSaveChanges
、以前と同じ例外が発生します。
古いオブジェクトを切り離すと、次のようになります。
try
{
ctx.SaveChanges();
// will throw an exception because customer 1 is already in DB
}
catch (DbUpdateException e)
{
ctx.Entry(customer).State = EntityState.Detached;
// customer is now detached from context and
// won't be saved anymore with the next SaveChanges
// create new object adn attach this to the context
var customer2 = new Customer { Id = 2, Name = "Y" };
ctx.Customers.Add(customer2);
ctx.SaveChanges();
// no exception
}
関係が関係している場合、この手順は難しい場合があります。たとえばcustomer
、注文のリストと関係があるcustomer
場合、注文がコンテキストにも添付されていると、オブジェクトをデタッチすると、顧客とその注文の間の参照が削除されます。新しいとの関係を再確立する必要がありcustomer2
ます。
したがって、アタッチされたオブジェクトを変更して、正しい状態にすることをお勧めします。または、このような制約違反は通常、コードのバグを示しているため、またはマルチユーザー環境では適切な楽観的同時実行性チェックで処理する必要があるため、アプリケーションをクラッシュさせます。