我希望这会很容易,但对于我的生活,我无法在SO或任何其他网站上找到具体答案。
我有一个基本的存储库/单元工作模式与Entity Framework Code First。除了某些更新案例外,一切顺利。问题是我有一组Entity Framework模型对象,所有对象都以EF返回的“Db”为前缀,但我将它们转换为普通的DataContract Model对象以传递给Web层以分离关注点。我有一个基本的转换接口,它只是从DataModel对象填充WebModel对象,逐字段逐字复制。
因此,如果从ID为1的EF检索DbUser对象,然后转换为User对象,然后将该BACK转换为DbUser对象,最终得到ID为1的DbUser,但它是一个DIFFERENT对象对于你开始使用的那个,虽然它们具有相同的主键字段,但实际的CLR对象本身是不同的。
以下作品
User user;
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
}
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser);
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
repository.Update(user);
repository.save();
}
因为他们正在使用两个不同的工作/上下文单元,所以第二个块在ObjectStateManager中没有任何内容可以比较,并且只能在Update()方法中附加分离的对象
然而,这不起作用
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser)
repository.Update(user);
repository.save();
}
注意:我在逻辑上知道这对转换没有多大意义,只是转换回来但是顺其自然,我已经大大简化了示例,使其更容易投入纸张,在我的实际代码中有一个原因这样做。
我得到通常的错误“objectstatemanager中已存在具有相同密钥的对象...”。我假设因为Get()将对象加载到EF中,然后更新看到对象已分离,然后尝试附加它并且它已经存在。
我的存储库中的My Update方法如下所示
public override bool UpdateItem(DbUser item)
{
if (Work.Context.Entry(item).State == EntityState.Detached)
Work.Context.Users.Attach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
答案 0 :(得分:1)
我将此扩展方法设置为DbContext以重新启动实体而没有问题尝试:
public static void ReAttach<T>(this DbContext context, T entity) where T : class
{
var objContext = ((IObjectContextAdapter) context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);
Object foundEntity;
var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
// Detach it here to prevent side-effects
if (exists)
{
objContext.Detach(foundEntity);
}
context.Set<T>().Attach(entity);
}
然后只需更新您的方法:
public override bool UpdateItem(DbUser item)
{
Work.Context.ReAttach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
答案 1 :(得分:0)
您可能会获得一个托管实体,并再次逐字地将新的DbUser
属性映射到托管对象:
public override bool UpdateItem(DbUser item)
{
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
DbUser managedUser = repository.Get(item.PK);
//foreach DbUser property map the item to managedUser
managedUser.field1 = item.field1;
[..]
repository.Update(managedUser);
repository.Save();
}
}
答案 2 :(得分:0)
如果您将上下文设置为AsNoTracking(),则会停止aspmvc跟踪内存中实体的更改(无论如何,这都是您想要的)。
_dbContext.Products.AsNoTracking().Find(id);
了解更多相关信息
佳日