In a DB-first EF6 application, we have a data access layer which handles all the interaction with EF.
The objects pulled from the context are EF-generated C# classes, these are then mapped to equivalent POCOs in the business layer. This is a common suggested approach as it decouples the layers.
So whilst the application is running, some objects in the business layer get changed (some new ones may be added also, others deleted). When the changes need to be saved to the DB, the objects are mapped back to the business layer. The problem is when EF receives these objects, it has no idea which entities have changed and which haven't.
What's a good way to approach this? (given that hundreds or thousands of objects may or may not have changed)
I've seen other projects solve this by keeping track of changes in lists: NewObjects, UpdatedObjects, DeletedObjects
. The obvious problem here is that whenever somethings changes, developers need to remember to update the appropriate list. This ends up with a lot of extra clutter, and it's very easy to make a mistake.
-
1EF6 has its own internal change tracking mechanism, so as long as you're willing to always map your business objects back to genuine EF entities (using an EF data context, in a read-update-save cycle), this should never be a problem.Robert Harvey– Robert Harvey08/03/2017 16:01:31Commented Aug 3, 2017 at 16:01
-
But the context is only opened in the DAL when the data is read from the DB, and then closed (else I'd need to hold it open). When the business objects are mapped backed to EF entities later on, I'd need to create a new context, which surely wouldn't have any knowledge of the objects in their original state when loaded? (and not know what has changed)FBryant87– FBryant8708/03/2017 16:07:20Commented Aug 3, 2017 at 16:07
-
1If you don't have a current context, you have to read the data from the DB immediately before updating it and calling SaveChanges().Robert Harvey– Robert Harvey08/03/2017 16:07:52Commented Aug 3, 2017 at 16:07
-
Aha I see, and then somehow compare that read data with the EF entities mapped back from the business layer, thank you. Are you aware of an example which demonstrates this comparison?FBryant87– FBryant8708/03/2017 16:10:14Commented Aug 3, 2017 at 16:10
-
EF performs the comparison. If nothing changes in the EF entity, nothing happens when you call SaveChanges().Robert Harvey– Robert Harvey08/03/2017 16:10:38Commented Aug 3, 2017 at 16:10
1 Answer 1
Entity Framework has its own change tracking mechanisms. Updating an EF entity could be as simple as this (if you're using AutoMapper):
var entity = context.Entities.First(e => e.Id == viewmodel.Id); // fetch the entity
Mapper.Map(viewmodel, entity); // Use automapper to update entity from viewmodel
context.SaveChanges();
-
In hindsight - one problem with this approach is that AutoMapper makes new instances of nested objects when mapped - so the context does not acknowledge these nested changes. Should these be added to the context also somehow?FBryant87– FBryant8708/09/2017 09:18:13Commented Aug 9, 2017 at 9:18
-
Nevermind - I needed to mark each nested object as EntityState.Modified (which seems odd - would EF tracker not be able to tell if something's been modified?)FBryant87– FBryant8708/09/2017 09:51:59Commented Aug 9, 2017 at 9:51
-
(and looks like this defeats the purpose of the change tracker, it's very slow as it tries to update everything even if just one entity has changed)FBryant87– FBryant8708/09/2017 10:01:14Commented Aug 9, 2017 at 10:01
-
I had db.Configuration.AutoDetectChangesEnabled = false (embarrasing!)FBryant87– FBryant8708/09/2017 10:44:20Commented Aug 9, 2017 at 10:44