¿Cómo saber si un objeto de Entity Framework ha cambiado?

I've an object which is called Uczestnik which just got saved to database

var konsultant = uczestnik.Konsultanci; 
uczestnik.Konsultanci = null; // null attached object and reuse it's ID later on for SAVE purposes
uczestnik.KonsultantNazwa = konsultant.KonsultantNazwa;
uczestnik.Szkolenie = null; // null attached object and reuse it's ID later on for SAVE purposes
uczestnik.SzkolenieID = szkolenie.SzkolenieID;                       
context.SzkolenieUczestnicies.AddObject(uczestnik);
context.SaveChanges();
context.Detach(uczestnik); // detatch to prevent Context problems
uczestnik.Szkolenie = szkolenie;// reassign for use in ObjectListView
uczestnik.Konsultanci = konsultant; // reassign for use in ObjectListView   

After it's saved it's back into ObjectListView where user decided to change some value and the value was changed (one value from multiple to be exact). If I check value's entity state it's in Unchanged state so calling .Attach and .SaveChanges() won't do anything. I can use ChangeObjectState but if there's nothing changed then there's no sense to do so.

context.SzkolenieUczestnicies.Attach(uczestnik);
//context.ObjectStateManager.ChangeObjectState(uczestnik, EntityState.Modified);
context.SaveChanges();

How can I detect the change and prevent unnecessary traffic (I can imagine situation where nothing is changed in the object that holds files 5mb big) so resaving it makes no sense. Unless Entity is smart enough to detect that only one field was changed from 15 and change only that field?

preguntado el 01 de febrero de 12 a las 22:02

Have you looked at ObjectContext.DetectChanges? -

No, wasn't aware of it? How would I use it? Also considering that context is enclosed in using wouldn't DetectChanges show nothing when it's executed on new context? -

2 Respuestas

If the entity is detached from a context you can't find out what has changed unless you are reloading the original entity from the database or you are using self-tracking entities or manage a tracking somehow yourself.

If you reload the entity you can use ApplyCurrentValues:

var originalEntity = context.MyEntities.Single(e => e.Id == detachedEntity.Id);
context.MyEntities.ApplyCurrentValues(detachedEntity);
context.SaveChanges();

This method marks the properties as modified which have different values between original and detached entity. SaveChanges will create an UPDATE statement which includes only those changed properties. If no property did change, SaveChanges no hace nada.

But you are not completely free from "unnecessary traffic" because you have to load the original entity, you will save an unnecessary UPDATE statement though.

Respondido 02 Feb 12, 03:02

Thanks, I guess the best way is to implement tracking like @Ladislav Mrnka suggested. This program is supposed to work thru WAN link and having Documents synchronized multiple times which can be small 500kb or large 20MB may be a killer if I decide to reload them from db. - Chico loco

Si Detach entity it is not tracked by the context. In such case you are responsible for detecting when the object has changed and inform the context about changes by using ChangeObjectState. So you must track what user has modified or implement something directly to your entities. For example implement INotifyPropertyChanged (if you are using EntityObject based entities this interface should be already implemented).

Respondido 02 Feb 12, 03:02

Can you show an example (or a link to one) how to inform context that only one value from 15 columns have changed so the update doesn't touch other 14 columns ? - Chico loco

Consulta este - Ladislav Mrnka

Thanks. Very useful. I saw some article about self-tracking entities with some changes like on this blog blogs.msdn.com/b/adonet/archive/2011/02/09/… Do you know if it's good idea or should I do it by hand using your way? - Chico loco

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.