我有一个使用web api 2开发的Web服务,它使用ef 6将数据保存回数据库。
我的数据结构如下;
public class User
{
[Key]
public int UserId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
}
public class Contact
{
[Key]
public int ContactId { get; set; }
public string ContactName { get; set; }
public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public User CreatedBy { get; set; }
public int ModifiedById { get; set; }
[ForeignKey("ModifiedById")]
public User ModifiedBy { get; set; }
}
public class Note
{
[Key]
public int NoteId { get; set; }
public string Notes { get; set; }
public int ContactId { get; set; }
[ForeignKey("ContactId")]
public Contact Contact { get; set; }
public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public User CreatedBy { get; set; }
public int ModifiedById { get; set; }
[ForeignKey("ModifiedById")]
public User ModifiedBy { get; set; }
}
我使用锅炉板代码尝试保存对web api中的注释的修改,如下所示
// PUT: api/Notes/5
[ResponseType(typeof(void))]
public IHttpActionResult PutNote(int id, Note note)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != note.NoteId)
{
return BadRequest();
}
db.Entry(note).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!AttachmentExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
但是当执行修改entitystate的行时,我得到以下异常。
附加“'用户”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。
我发现这令人费解,因为我没有手动附加任何entites并且此时db.ChangeTracker.Entries()为空。我原以为EF会处理同一个实体可以在树中多次引用的事实。
有没有人遇到过这个,有没有人有解决方案呢?
非常感谢,
尼尔。
答案 0 :(得分:0)
我认为部分问题在于,您的笔记模型可能永远无法正确加载到EF的对象图中进行跟踪。
尝试以下伪(ish)代码:
// PUT: api/Notes/5
[ResponseType(typeof(void))]
public IHttpActionResult PutNote(int id, Note note)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
if (id != note.NoteId)
return BadRequest();
//Not sure how you're setup, but have EF fetch the note you want
//to modify from the DB. It is now aware of it and tracking changes.
var model = _getNoteModelFromDbById(note.NoteId);
//Now that you have the model from the DB you can map the properties
//of the incoming note to your model. Bellow is just a basic example.
//I recommend you look into a library called Automapper later on.
model.Title = note.Title;
model.Description = note.Description;
model.Status = note.Status;
db.Entry(model).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!AttachmentExists(id))
return NotFound();
else
throw;
}
return StatusCode(HttpStatusCode.NoContent);
}