我使用NoTracking获取对象,转换并操作它,将其发送到asp.net mvc视图。我找回一个已编辑的版本,在我的存储库中调用edit方法,尝试附加它,它会抛出以下错误:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
我如何获取数据:
IQueryable<User> query = db.Users.AsNoTracking();
我如何编辑数据:
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;
}
当我使用AsNoTracking
获取实体时,不应该为我分离这些内容吗?即使它没有分离,整个asp.net生命周期也应该在重新提交数据时重新启动,这会使图表变空。
我在这里做错了什么?
我做这样的绑定:
DbContext db = new DbContext("ConnStringName");
Bind<IUserRepository>().To<SqlServerUserRepository>()
.WithConstructorArgument("db", db);
答案 0 :(得分:1)
听起来您的数据库上下文是一次创建的,并且该实例实际上是一个单例。当您尝试附加User
时,上下文检测到它已经在缓存中有一个并且失败。
我建议更改每个请求创建的上下文。使用Ninject,您可以将其与
绑定Bind<YourDbContext>().ToMethod(context => CreateContext()).InRequestScope();
其中YourDbContext
是db
变量的类型,而CreateContext()
是global.ascx中的方法。
<强>更新强>
您确实创建了一次数据库上下文并将其存储为单例。不用担心,您可以将绑定设置为
// DbContext db = new DbContext("ConnStringName");
Bind<DbContext>().ToMethod(context => new DbContext("ConnStringName")).InRequestScope();
Bind<IUserRepository>().To<SqlServerUserRepository>().InRequestScope();
这将为每个请求创建一个新的DbCOntext,并防止缓存的User
在附加时与提交的User
发生冲突。