tabs ↹ over ␣ ␣ ␣ spaces

by Jiří {x2} Činčura

Updating entity from DTO without fetching it

11 Nov 2016 Entity Framework

Last week I was talking with colleague and we went deep into using DTOs for showing data effectively and also updating such data back. This topic itself could be discussed for hours. But what got my attention was whether I could make the update back to database from DTO a little bit more like if the change tracking was kickin’ in automatically on tracked object.

Of course that needs some manual work, because else the infrastructure does not know what was changed and what was not. You can of course handle it like everything was change, but that also means you have to construct complete entity from the DTO, which might not be possible because the DTOs often don’t have all the data. Something like the idea for deletes without first fetching the entity, because you actually need just the ID.

So the flow in my head was like this.

  • Fetch data into DTO.
  • Change the DTO.
  • Create stub entity from the DTO - basically just ID and changed values (this is where some automapper-like libraries help a lot).
  • Update the entity (only the changed values, of course) using regular SaveChanges.

I knew it’s not going to be some hacking, just regular use of change tracker. But I also wanted it to feel seamless. I was not sure whether the method should be on DbContext or DbEntityEntry<T>. At the end I chose DbContext because I felt hiding the Entry<T> call is helpful.

public static void ApplySelectedValues<TEntity>(this DbContext context, TEntity entity, params Expression<Func<TEntity, object>>[] properties) where TEntity : class
	var entry = context.Entry(entity);
	entry.State = EntityState.Unchanged;
	foreach (var prop in properties)
		entry.Property(prop).IsModified = true;

As I said I, it’s just a regular use of change tracker. To attach the entity I set the State to Unchanged, thus I don’t have to fiddle with Attach method. Then it’s just simple loop over properties the caller declared to be modified and telling that to Entity Framework.

With this I can write code like this.

using (var ctx = new MyContext())
	ctx.Database.Log = Console.WriteLine;
	var dto = new
		Id = 25,
		A = 66,
	// manual shoveling of the data
	var entity = new Entity()
		Id = dto.Id,
		A = dto.A,
		B = default(int),
		x => x.A);

And the generated update statement will update only the column A, leaving the B untouched, because ApplySelectedValues said only A was changed.

Honestly I thought it’s going to be a little more fiddling. But simple code is a good code. Especially for people - not like me - not interested in fiddling.