我正在寻找一种水合相关物体的简单方法。注释属于文档,只有文档的所有者才能添加注释,因此当用户尝试编辑注释时,我需要对相关文档进行水合以找出用户是否可以访问它。在我的服务层中,我有以下内容:
public void editNote(Note note)
{
// Get the associated Document object (required for validation) and validate.
int docID = noteRepository.Find(note.NoteID).DocumentID;
note.Document = documentRepository.Find(docID);
IDictionary<string, string> errors = note.validate();
if (errors.Count > 0)
{
throw new ValidationException(errors);
}
// Update Repository and save.
noteRepository.InsertOrUpdate(note);
noteRepository.Save();
}
问题是,noteRepository.InsertOrUpdate(注释)抛出一个异常,“ObjectStateManager中已经存在一个具有相同键的对象”。当存储库设置EntityState.Modified时。所以出现了一些问题:
我问了一个与此相关的类似问题,但不是很清楚,所以希望这个版本能让人理解,从而指出我正确的方向。
修改
根据Ladislav Mrnka提供的信息和此处详述的答案:An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key,我的存储库方法似乎需要如下所示:
public void InsertOrUpdate(Note note)
{
if (note.NoteID == default(int)) {
// New entity
context.Notes.Add(note);
} else {
// Existing entity
//context.Entry(note).State = EntityState.Modified;
context.Entry(oldNote).CurrentValues.SetValues(note);
}
}
但是如何从上下文中获取oldNote呢?我可以调用context.Entry(Find(note.NoteID))。CurrentValues.SetValues(注释)但是我在这里引入了潜在的问题吗?
答案 0 :(得分:0)
我是否正确接近这个,如果是这样,我该如何解决这个例外?
我想这段代码会从数据库中加载整个Node来查找DocumentID:
int docID = noteRepository.Find(note.NoteID).DocumentID;
在这种情况下,您的InsertOrUpdate无法获取您的节点并将其附加到具有“已修改”状态的上下文,因为您已在上下文中使用相同的键进行注释。常见的解决方案是使用它:
objectContext.NoteSet.ApplyCurrentValues(note);
objectContext.SaveChanges();
但是对于编辑,我不能使用它,因为恶意用户可以提供他们有权访问的DocumentID,从而编辑他们不拥有的Note。
在这种情况下,您必须添加一些安全性。您可以将任何数据添加到页面中的隐藏字段中,但客户端不得更改的那些数据必须包含一些额外的安全性。例如,第二个隐藏字段,其中包含在服务器上计算的签名或在服务器上计算的盐值的哈希值。当数据在下一个请求返回到服务器时,它必须重新计算并将签名/哈希与相同的盐进行比较,并验证传递的值和计算值是否相同。当然,客户端必须不知道您用于计算哈希中使用的签名或盐的秘密。
我已经读过我应该将文档存储库作为聚合并丢失Note存储库,但不确定是否/如何帮助。
这是使用存储库的更简洁方法,但它无法帮助您解决特定错误,因为您仍需要Note
和DocumentId
。