2012-07-26 9 views
14

ナビゲーションプロパティの変更を検出しません名前と住所の両方のプロパティが割り当てられたPerson型のオブジェクト。私の問題は、データベースからPersonオブジェクトをフェッチして、Addressプロパティ(Nullなど)を変更した場合、e.f.変更を検出しません! 私のコードはこれです:Entity Frameworkのは、私は、ナビゲーションプロパティの変更を検出してトラブルを抱えている

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.First(); 
    //p.Address IS NOT NULL! 
    p.Address = null; 
    var entry = ctx.Entry(p); 
} 

なぜentry.State変わらないのですか?

編集: SaveChangesを呼び出すと、レコードが正しく保存されます(アドレスはnullになります)。

編集2:私は外部キープロパティをビリーとして提案しました。ビジュアルスタジオのPersonオブジェクトを検査すると状態は変更されます。オブジェクトの値を検査するデバッガで停止しないと、状態は変わらない!

編集3: ctx.People.Include(x => x.Address).First();を使用してPersonオブジェクトを読み込みます。問題を解決します。 Includeを呼び出してAddressIdプロパティの代わりにAddressプロパティを変更し続ける方法はありますか?

+0

ctx.DetectChanges()を呼び出すとどうなりますか? – Maarten

+0

何もありません。結果は同じです!! – Mones

答えて

24

まず、Includeを使用するには@ビリーの助言に従わなければなりません。 "p.Address IS NOT NULL!"は、デバッガでp.Addressを見て、デバッガで遅延ロードをトリガしているため、アドレスがnullに変更されたことが検出されたためです。リリースモードまたはデバッガのプロパティを検査しないと、コードが機能せず、変更が保存されません。

だから、あなたの編集3への答えは次のとおりです。

第二号:var entry = ctx.Entry(p)だけより正確に代わり関係状態、またはをエンティティが述べて、あなたは、エンティティの状態を変更しなかったが、返しますは、の関係を削除しました。あなたはDbContext APIとの関係の状態を検査することができないだけObjectContext APIで:

enter image description here

EFは、この関係のエントリを検討します:

Person p = ctx.People.Include(x => x.Address).First(); 
p.Address = null; 
var objCtx = ((IObjectContextAdapter)ctx).ObjectContext; 
var objentr = objCtx.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted); 

objentrは今タイプRelationshipEntryのエントリを持っていますSaveChanges()に電話してその関係を削除したときにエンティティの状態エントリとともにデータベース内のPersonの外部キー列Addressをに設定します。

編集2:外部キープロパティ(モデル内のスカラープロパティ)を変更すると、エンティティ自体が変更されるため、エンティティの状態はこの場合はModifiedになります。

+0

うわー!本当に良い答えに感謝! –

+0

素敵な答えですが、疑いがあります。これは特定のコンテキストへのクエリであるため、特定のエントリがこの変更に苦しんでいて他のエントリには苦しんでいないことをどのように識別しますか。 –

+0

'ObjectContext'がないので、EF Coreでこれをどうやってやりますか? – grokky

5

アドレスナビを含める必要があります。小道具あなたが保存するときに、あなたのクエリで、それ以外のEFは、それへの変更を検討しません:あなたはまた、私はとても好きなモデルで外部キーを使用することができ

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.Include(x => x.Address).First(); 
    //p.Address IS NOT NULL! 
    p.Address = null; 
    var entry = ctx.Entry(p); 
} 

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

    public string Name { get; set; } 

    public virtual Address Address { get; set; } 

    public int? AddressId {get; set;} 
} 

...

using (var ctx = new EFContext()) 
{ 
    Person p = ctx.People.First(); 
    p.AddressId = null; 
    var entry = ctx.Entry(p); 
} 
+0

私はDetectChangesでこのソリューションをテストしましたが、方法は変わりません。私はintを使用する場合?外部キー私は、 "単純な"プロパティの値を変更し、ナビゲーションプロパティを直接変更するつもりはないので、正しく動作すると思います。実際、PersonオブジェクトのNameプロパティを変更すると、すべてOkです! – Mones

2

私のアプリケーションでは、リロードが要求されるか、ユーザーがアイテム/ビューを終了する前に、保存されていない変更がないことを確認するためにいくつかのチェックを行います。

これは基本的に現在受け入れられている回答を実行していますが、ObjectContext.ObjectStateManagerがリレーションシップの変更を取得する前にContext.ChangeTracker.DetectChanges()に電話する必要があることに注意してください。これをデバッグするのにかなり時間を費やしました。

_EagleContext.ChangeTracker.DetectChanges(); 

var objectContext = ((IObjectContextAdapter)_EagleContext).ObjectContext; 
var changedEntities = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified); 

if (_EagleContext.ChangeTracker.Entries().Any(e => e.State == EntityState.Modified) 
    || changedEntities.Count() != 0) 
{ 
    var dialogResult = MessageBox.Show("There are changes to save, are you sure you want to reload?", "Warning", MessageBoxButton.YesNo); 
    if (dialogResult == MessageBoxResult.No) 
    { 
     return; 
    } 
} 

// Continue with reloading... 
関連する問題