有大量关于这方面的信息,但即使在阅读了几个小时之后,我似乎也无法让它按照我想要的方式工作。
我试图通过传入一个用户对象并一般比较我从数据库中提取的用户对象的更改来更新用户对象。使用此方法时,我总是最终得到 NotSupportedException:
An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
这是我尝试的方法:
public void SaveUser(User User)
{
using (DataContext dataContext = new DataContext(WebConfigurationManager.ConnectionStrings["database"].ConnectionString))
{
// New user
if (User.UserID == 0)
{
dataContext.Users.InsertOnSubmit(User);
}
// Existing user
else
{
User dbUser = dataContext.Users.Single(u => u.UserID.Equals(User.UserID));
Type t = dbUser.GetType();
foreach (PropertyInfo p in t.GetProperties())
{
if (p.CanWrite & p.GetValue(dbUser, null) != p.GetValue(User, null))
{
p.SetValue(dbUser, p.GetValue(User, null), null);
}
}
//dataContext.Refresh(RefreshMode.KeepCurrentValues, dbUser);
}
dataContext.SubmitChanges();
}
}
注释掉的行我也尝试取消注释,但没有帮助。
如果我注释掉 foreach() 循环并添加一行,如 dbUser.UserName = "Cheese";它将很好地更新数据库中的用户名。这让我相信 foreach() 循环如何更改 dbUser 对象导致此失败。
当我调试 dbUser 对象时,它似乎正确地从作为参数传递的 User 对象获取所有更改。
我还阅读了一些关于乐观并发的内容,并向数据类型时间戳的表中添加了一列,但这似乎也没有任何效果。
我到底做错了什么?
如何才能让它一般性地检测已更改的内容并正确地将更改保存到数据库?
最佳答案
我的猜测是,您正在尝试复制一个最初未加载的外键关系(由于延迟加载)。在复制过程中,它正在尝试加载它,但 DataContext 已被释放。
我一直在解决类似的问题。我最终使用 AutoMapper 来为我处理属性的复制。我已将 AutoMapper 配置为忽略主键字段以及任何关系。像这样的东西:
public void Update(User user)
{
using (var db = new DataContext(...))
{
var userFromDb = db.Users.Where(x => x.Id == user.Id).Single();
AutoMapper.Mapper.Map(user, userFromDb);
db.SubmitChanges();
}
}
我的自动映射器配置类似于
AutoMapper.Mapper.Create<User, User>().ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.SomeRelation, opt => opt.Ignore());
您可以在这里找到 AutoMapper:http://automapper.codeplex.com/
关于database - Linq to Sql - 如何使用存储库模式更新对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4840295/