我正在研究包含桌面(Windows窗体)和Windows Phone应用程序的学校项目。错误发生在Api Controller,编辑操作中。
这是WebApi Call:
HttpResponseMessage responseProizvodi;
if (proizvod.ProizvodID == 0)
responseProizvodi = proizvodiService.PostResponse(proizvod);
else responseProizvodi = proizvodiService.PutResponse(proizvod.ProizvodID,proizvod);
我在WebApiHelper类中的方法:
public HttpResponseMessage PostResponse(Object o)
{
return client.PostAsJsonAsync(route, o).Result;
}
public HttpResponseMessage PutResponse(int id, Object o)
{
return client.PutAsJsonAsync(route + "/" + id, o).Result;
}
和使用Entity Framework生成的ApiController:
[ResponseType(typeof(void))]
public IHttpActionResult PutProizvodi(int id, Proizvodi proizvodi)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != proizvodi.ProizvodID)
{
return BadRequest();
}
db.Entry(proizvodi).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProizvodiExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
在这一行:
db.Entry(proizvodi).State = EntityState.Modified;
我收到了这个错误:
其他信息:附加类型' WebApi.Models.Proizvodi'失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。
我在类似的主题上阅读了问题/答案,但我没有找到答案。
其中一个人说我们必须分离本地版本并设置修改我们正在修改的实体。
这样做的一种方法是在DbSet的本地内部导航,看看这个是否在那里。如果该实体存在,则比您分离。
var local = yourDbContext.Set<YourModel>()
.Local
.FirstOrDefault(f => f.Id == yourModel.Id);
if (local != null)
{
yourDbContext.Entry(local).State = EntityState.Detached;
}
yourDbContext.Entry(applicationModel).State = EntityState.Modified;
在我的情况下,local为null,并且EntityState是Deatached,但我仍然有同样的错误。有帮助吗?
编辑: 我的数据库在这里:
public class ProizvodiController : ApiController
{
private eProdajaEntities db = new eProdajaEntities();
//actions
}
答案 0 :(得分:0)
EF不会跟踪传递给Proizvodi
方法的PutProizvodi
对象(即它不知道它来自何处,因为它不参与实体实例的创建;该实例是由Web.API模型绑定器创建的,它不知道您的数据库或EF)这可能是它抛出错误的原因。
仅仅因为Proizvodi
类型是实体类型,并不意味着EF会自动跟踪它;只跟踪EF检索到的对象。
您需要首先获取正确Proizvodi
对象的实例,方法是先使用您传递给id
方法的PutProizvodi
通过EF查找,而不是使用模型绑定器传入的Proizvodi
实例。
您可以使用Proizvodi
对象传递到您的PutProizvodi
方法,但更常见的是创建具有类似属性的模型,然后映射到您的实体实例按要求。这允许您控制实体对象的哪些属性传入和传出应用程序。
这样的事情: -
[ResponseType(typeof(void))]
public IHttpActionResult PutProizvodi(int id, ProizvodiModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// lookup the entity using the id that was passed in
var proizvodi = db.Set<Proizvodi>().Where(x => x.id == id).FirstOrDefault();
// if no entity was found with that id, return
if (proizvodi == null) {
return BadRequest();
}
// make the changes to your entity
proizvodi.SomeProperty = model.SomeProperty;
// etc
// then save the changes
db.SaveChanges();
return StatusCode(HttpStatusCode.NoContent);
}
public class ProizvodiModel
{
public string SomeProperty { get; set; }
}
答案 1 :(得分:0)
我意识到问题出在我的案例中。简而言之,我做了以下事情:
1
[4 5 5 6 7 8 8 8 8 9]
[2 8 9 3 8 4 5 7 9 7]
1.1
WebAPIHelper proizvodiService = new WebAPIHelper("http://localhost:62312/", "api/Proizvodi");
2
private Proizvodi proizvod { get; set; }
3
HttpResponseMessage responseProizvodi=proizvodiService.GetResponse(ProizvodID);
关键是,我从数据库(对象“proizvod”这个类中的私有属性)得到的同一个对象,我发送回数据库,那就发生了错误。
对象“p”指向数据库中的对象,然后对象“proizvod”指向同一个对象,同一地址,我做一些编辑,一切都放到对象“proizvod”并发送到PutResponse方法。
Proizvodi p = responseProizvodi.Content.ReadAsAsync<Proizvodi().Result;
proizvod = p;
// do some edit on "proizvod" and put to database
HttpResponseMessage responseProizvod = proizvodiService.PutResponse(proizvod.ProizvodID,proizvod);
缺失...现在每个工作都很好。我希望我意识到问题是什么。如果有人能够在技术上和精确地解释发生的事情,我会很高兴。我是一个初学者,并试图找出工作原理,谢谢。