Reputation: 57469
I get the object, using NoTracking, convert and manipulate it, send it to an asp.net mvc view. I get back an edited version, call the edit method in my repository, try to Attach it, it throws the following error:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
How I get the data:
IQueryable<User> query = db.Users.AsNoTracking();
How I edit the data:
public User UpdateUser(User user, IEnumerable<Expression<Func<User, object>>> properties)
{
db.Users.Attach(user); //Error happens right here.
foreach (var selector in properties)
{
string propertyName = Helpers.PropertyToString(selector.Body);
db.Entry(user).Property(propertyName).IsModified = true;
}
db.SaveChanges();
return user;
}
When I get the entities using AsNoTracking
, shouldn't that detach the thing for me? Even if it didn't detach, the whole asp.net life cycle is supposed to be restarted on resubmitting the data, which would make the graph empty.
What am I doing wrong here?
I do my bindings like this:
DbContext db = new DbContext("ConnStringName");
Bind<IUserRepository>().To<SqlServerUserRepository>()
.WithConstructorArgument("db", db);
Upvotes: 2
Views: 768
Reputation: 6932
Sounds like your db context is created once and that instance is effectively a singleton. When you attempt to attach the User
, the context detects that it already has one in the cache and fails.
I recommend changing the context to be created per request. With Ninject, you can bind it with
Bind<YourDbContext>().ToMethod(context => CreateContext()).InRequestScope();
where YourDbContext
is the type of the db
variable and CreateContext()
is the method in your global.ascx.
UPDATE
You are indeed creating your database context once and storing it as a singleton. No worries, you can set up your bindings as
// DbContext db = new DbContext("ConnStringName");
Bind<DbContext>().ToMethod(context => new DbContext("ConnStringName")).InRequestScope();
Bind<IUserRepository>().To<SqlServerUserRepository>().InRequestScope();
This will create a new DbCOntext for each Request and prevent the cached User
from colliding with the submitted User
when attaching.
Upvotes: 1