2011-10-25 10 views
14

Entity Framework 4.0を使用してWPFアプリケーションを作成しています。オブジェクトを保存しようとするとプライマリキー例外が発生しますが、プライマリキーはAutoIncrementedフィールドであり、例外の理由を理解できません。エンティティフレームワークがナビゲーションプロパティの値を挿入しないようにする

これを試した後、少しデバッグしてSQLプロファイラを使用した後、オブジェクトを挿入する前に、そのオブジェクトのナビゲーションプロパティを設定したときにレコードを親テーブルに挿入する必要があります。

Employeeオブジェクトを挿入し、その部門をEmployee.Department = deptObjectとして設定しようとすると、新しいレコードが部門オブジェクトに挿入されるように設定されます。

ナビゲーションプロパティオブジェクトがデータベース、プロパティ、またはメソッドに挿入されないようにと、私はちょっとお勧めします。あなたは従業員に部署を設定すると

+0

は何ですか主キーの例外?あなたのモデルの主キープロパティ 'StoreGeneratedPattern'を' Identity'に設定していないかもしれません。これは、あなたが見ていくつかのコードサンプルを提供していない場合は? – philt5252

答えて

40

これは、デタッチエンティティを誤って使用した場合のEFの動作方法です。私はあなたがこのようなものを使用しているとします

var employee = new Employee(); 
employee.Department = GetDepartmentFromSomewhere(departmentId); 

... 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.SaveChanges(); 
} 

このコードでは、従業員のエンティティを作成し、既存の部門への参照を追加し、データベースに新しい従業員を救いました。問題はどこだ?問題はAddObjectが従業員だけを追加するのではなく、オブジェクトグラフ全体を追加するということです。それがEFの仕組みです。オブジェクトの一部がコンテキストに接続されていて、そうでない部分にオブジェクトグラフがあることはできません。 AddObjectは、グラフ内のすべてのオブジェクトを新しいものとして追加します(新しいものはデータベースに挿入します)。そのため、操作の順序を変更するか、エンティティの状態を手動で修正して、部門がすでに存在することをコンテキストに認識させる必要があります。

using (var context = new YourContext()) 
{ 
    var employee = new Employee(); 
    ... 
    context.Employees.AddObject(employee); 

    employee.Department = context.Departments.Single(d => d.Id == departmentId); 
    context.SaveChanges(); 
} 

第二の溶液 - 個別のコンテキストにエンティティを接続し、その後のエンティティ間の参照を行います: -

まずソリューションロード部門の同じ文脈と保存の従業員を使用し

var employee = new Employee(); 
... 

var department = GetDepartmentFromSomewhere(departmentId); 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.Departments.Attach(department); 
    employee.Department = department; 

    context.SaveChanges(); 
} 

サード解決策 - 部門の正しい状態を手動で入力して、コンテキストに再度挿入しないようにします。

var employee = new Employee(); 
employee.Department = GetDepartmentFromSomewhere(departmentId); 

... 

using (var context = new YourContext()) 
{ 
    context.Employees.AddObject(employee); 
    context.ObjectStateManager.ChangeObjectState(employee.Department, 
               EntityState.Unchanged); 
    context.SaveChanges(); 
} 
+1

ありがとうございました。私はあなたのために唯一の言葉を持っています。 –

+0

私は 'DbContext'から派生したクラスを使用し、以下は' DbContext'の第3の解決策と同じ効果を持っています 'context.Entry(employee.Department).State = EntityState.Unchanged;' – twnaing

+3

3番目の解決策では、 Departmentオブジェクトはまだ別の関係を持っていますか? AddObjectフラグには、そのすべてが追加されていますか?どのようにして再帰的に物事を変わらずに戻すことができますか? – Bobson

0

おかげで - 私はあなたが部門を確認する必要があることだと思うが、DBから取得して、それが実体を添付しました。
また、部門ナビゲーションプロパティを設定する代わりに、deprtmentのID(外部キープロパティ)を設定することもできます。

1

私はLadislavsの素晴らしい答えですでに提供されている3つのソリューションに加えて、4番目のソリューションを追加したいと考えています。事実、Naorの短い答えの詳細なバージョン。私は6


ではなく、部門オブジェクトの従業員にdeparment IDを割り当てるエンティティフレームワークのバージョンで働いている私は、に加えて、「外部キーの値」プロパティを持っている傾向がある

私のモデルクラスのナビゲーションプロパティ。

のでEmployeeクラスに私はDepartment財産ともint型のDepartmentIdを(その可能であればEmployeeは何Departmentを持っていないことをint型NULL可能にします)があります。

public class Employee 
{ 
    public int Id { get; set; } 

    public String EmployeeName { get; set; } 


    #region FK properties 

    public Department Department { get; set; } 

    public int? DepartmentId { get; set; } 

    #endregion 
} 

あなたは今、何ができるだろうさ代わりにそう :ちょうどDepartmentIdを設定するだけで設定

employee.Department = departmentObject; 

0追加の従業員に SaveChangesを呼び出すとき
employee.DepartmentId = departmentObject.Id; 

または

employee.DepartmentId = departmentid 

は今、唯一の従業員が保存されますし、新しい部署が作成されません。ただし、EmployeeからDepartmentへの参照は、部門IDが割り当てられているため正しく設定されています。


詳細情報

私は通常/処理の従業員を読​​み込む場合にのみEmployeeクラスのDepartmentオブジェクトにアクセスします。 従業員を作成または更新するときは、EmployeeクラスのDepartmentIdプロパティを使用して割り当てます。 EmployeeDepartmentプロパティに割り当てない

は1つの欠点があります。それはより困難なデバッグ作ることができ、SaveChangesを呼び出して、従業員を再読み込みする前に、EmployeeDepartmentオブジェクトを参照するか、または使用することはできないので。 EF6内のエンティティの状態情報

を修正


これは、そのように行われているEF6でLadislavsソリューション番号3

を参照:

_context.Entry(employee.Department).State = EntityState.Unchanged; 
関連する問題