public static class Helpers
{
public static Ent LoadStub<Ent>(this DbContext db, object id) where Ent : class
{
string primaryKeyName = typeof(Ent).Name + "Id";
return db.LoadStub<Ent>(primaryKeyName, id);
}
public static Ent LoadStub<Ent>(this DbContext db, string primaryKeyName, object id) where Ent: class
{
var cachedEnt =
db.ChangeTracker.Entries().Where(x => ObjectContext.GetObjectType(x.Entity.GetType()) == typeof(Ent)).SingleOrDefault(x =>
{
var entType = x.Entity.GetType();
var value = entType.InvokeMember(primaryKeyName, System.Reflection.BindingFlags.GetProperty, null, x.Entity, new object[] { });
return value.Equals(id);
});
if (cachedEnt != null)
{
return (Ent) cachedEnt.Entity;
}
else
{
Ent stub = (Ent) Activator.CreateInstance(typeof(Ent));
typeof(Ent).InvokeMember(primaryKeyName, System.Reflection.BindingFlags.SetProperty, null, stub, new object[] { id });
db.Entry(stub).State = EntityState.Unchanged;
return stub;
}
}
}
So instead of using this pattern:
movie.Genres = movie.Genres ?? new List<Genre>();
movie.Genres.Clear();
foreach (int g in input.SelectedGenres)
{
DbEntityEntry<Genre> cachedGenre = db.ChangeTracker.Entries<Genre>().SingleOrDefault(x => x.Entity.GenreId == g);
Genre gx = null;
if (cachedGenre != null)
gx = cachedGenre.Entity;
else
{
gx = new Genre { GenreId = g };
db.Entry(gx).State = EntityState.Unchanged;
}
movie.Genres.Add(gx);
}
We could now use this:
movie.Genres = movie.Genres ?? new List<Genre>();
movie.Genres.Clear();
foreach (int g in input.SelectedGenres)
movie.Genres.Add(db.LoadStub<Genre>(g));
Sample use: http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html