EF 4.3.1でコンソールテストプロジェクトを作成しました。コードは私の推測であり、あなたのコメント行とコメントの下にあなたのコメント(私の推測はおそらくプログラムがあなたのエラーを再現しないので、間違っていると思われます):
あなたはprogram.csにコードをコピーし、 EF 4.3.1への参照を追加してください:
using System.Data;
using System.Data.Entity;
namespace EFUpdateTest
{
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int SubObjectId { get; set; }
public SubObject SubObject { get; set; }
}
public class SubObject
{
public int Id { get; set; }
public string Something { get; set; }
}
public class CustomerContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<SubObject> SubObjects { get; set; }
}
class Program
{
static void Main(string[] args)
{
int customerId = 0;
int subObject1Id = 0;
int subObject2Id = 0;
using (var ctx = new CustomerContext())
{
// Create customer with subobject
var customer = new Customer { Name = "John" };
var subObject = new SubObject { Something = "SubObject 1" };
customer.SubObject = subObject;
ctx.Customers.Add(customer);
// Create a second subobject, not related to any customer
var subObject2 = new SubObject { Something = "SubObject 2" };
ctx.SubObjects.Add(subObject2);
ctx.SaveChanges();
customerId = customer.Id;
subObject1Id = subObject.Id;
subObject2Id = subObject2.Id;
}
// New context, simulate detached scenario -> MVC action
using (var ctx = new CustomerContext())
{
// Changed customer name
var customer = new Customer { Id = customerId, Name = "Jim" };
ctx.Customers.Attach(customer);
// Changed reference to another subobject
var subObject2 = ctx.SubObjects.Find(subObject2Id);
customer.SubObject = subObject2;
ctx.Entry(customer).State = EntityState.Modified;
ctx.SaveChanges();
// No exception here.
}
}
}
}
これは例外なく動作します。問題は、エラーの原因となる可能性のあるコードとは何が違うのですか?
編集
あなたは、顧客のクラスに外部キープロパティSubObjectId
を持っていないあなたのコメントに:私は、エラーを再現できる上に、私はプログラム例ではプロパティを削除した場合。
ソリューションを使用すると、関係変更する前に、データベースから元のサブオブジェクトをロードすることです:
// Changed customer name
var customer = new Customer { Id = customerId, Name = "Jim" };
ctx.Customers.Attach(customer);
// Load original SubObject from database
ctx.Entry(customer).Reference(c => c.SubObject).Load();
// Changed reference to another subobject
var subObject2 = ctx.SubObjects.Find(subObject2Id);
customer.SubObject = subObject2;
ctx.Entry(customer).State = EntityState.Modified;
ctx.SaveChanges();
// No exception here.
外部キープロパティがなければ、あなたが独立協会持つオブジェクトは、すべての参照を含むことが必要です変更する前にデータベースの状態を表す必要があります。 SubObject
の参照をcustomer
に設定しない場合、EFはデータベースの元の状態がそのサブジェクトを参照していないことを前提としています。 UPDATE文の生成されたSQLは、次のようなWHERE句が含まれます。顧客はDB [SubObject_Id]
でサブオブジェクトを持っている場合
WHERE [Customers].[Id] = 1 AND [Customers].[SubObject_Id] IS NULL
をないでNULL、条件が満たされないとUPDATEが発生しません(または「予期しない行数0」で起こる)。
あなたが外部キープロパティを持っている場合、問題は発生しません(外部キー協会は):この場合の句は唯一であるザ・WHERE:だから
WHERE [Customers].[Id] = 1
、元だかは重要ではありませんSubObject
およびSubObjectId
の値。それでも、値null
のままにすることはできますが、UPDATEは機能します。関係が必要とされていない場合には、
public int SubObjectId { get; set; }
または::
public int? SubObjectId { get; set; }
はまた、あなたを行います
したがって、本来のサブオブジェクトをロードする代替ソリューションは
Customer
に外部キープロパティを導入することですコメントの後ろに隠れているコードを削除するとエラーが発生しますか?そうでない場合は、この隠しコードをより詳細にスケッチすると役立つかもしれません。 'Refresh'を使ってオブジェクトグラフの更新を取得する必要性は、「正常ではありません」です。 – Slaumaコメントのコード(この記事では非表示)は、このサブオブジェクトのインスタンスを顧客に取得するためのサブオブジェクトへのクエリです。これは、クライアントがコンボボックス内で新しい値を選択し、データベースからオブジェクトを戻して顧客に割り当てることができるためです(顧客のFKを更新することを目標としています)。 –
サブオブジェクトを取得するために同じコンテキスト 'myDbContext'を使用していますか? 'Customer'クラスのサブオブジェクトの外部キープロパティを持っていますか? – Slauma