我有一个非常简单的MVC5 WebApi项目,其中包含以下模型:
public class Product
{
public Product()
{
}
public int ProductId { get; set; }
public string ProductCode { get; set; }
public int BomId { get; set; }
public virtual BOM BOM { get; set; }
}
public class BOM
{
public BOM()
{
Products = new List<Product>();
}
public int BomId { get; set; }
public string Description { get; set; }
public int Counter { get; set; }
public virtual List<Product> Products { get; set; }
}
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<BOM> BOMs { get; set; }
}
这是PUT动作(脚手架动作):
public IHttpActionResult PutProduct(int id, Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != product.ProductId)
{
return BadRequest();
}
db.Entry(product).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
当代码执行db.SaveChanges();代码按预期执行,但数据库没有更新。
以下是控制台应用程序中触发PUT请求的代码:
static async Task UpdateProduct(int Id)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost.fiddler:49195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/products/" + Id.ToString());
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
Product product = JsonConvert.DeserializeObject<Product>(json);
product.BOM.Counter += 1;
json = JsonConvert.SerializeObject(product);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
response = await client.PutAsync("api/products/" + Id.ToString(), httpContent);
Console.WriteLine(response.IsSuccessStatusCode.ToString() + ": Counter = " + product.BOM.Counter);
}
}
}
此方法的作用是获取所请求的产品(1),通过递增该字段上的值来更新子项(BOM.Counter)中的字段。
只是数据库没有更新,所以当应用程序再次启动时,显然我们得到的是旧值而不是更新的值。 SaveChanges方法似乎已执行,但数据库并未建议它具有。
根据Fiddler2:
,这是来自PUT方法的get和put json字符串
注意: 我在Global.asax文件中有这些代码行,以便Json正确处理模型:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
我希望有人能看到我出错的地方。任何帮助都会非常感激。
提前致谢,
保罗。
答案 0 :(得分:1)
看两行代码:
Product product = JsonConvert.DeserializeObject<Product>(json);
product.BOM.Counter += 1;
你的问题是因为你有一个带有子实体的父实体,你将父实体的状态设置为Modified,但实际上改变的是子实体,所以你让孩子的实体状态保持不变(实体框架)确实将修改后的状态应用于单个实体,而不是像“已添加”那样将应用于整个图形,因此在服务器端,如果您只是将BOM实体状态设置为Modified,您将获得对数据库的更改。 / p>
现在我建议的不是永久解决方案,但这只是为了向您展示您的问题以及如何临时解决。
要永久解决它并且因为您的客户端是断开连接的图形,您的客户端需要跟踪对象并负责图形实体发生的事情(添加,修改,删除或未更改)。
您需要实现类似IObjectState的接口,让您的客户端更改断开连接的图形的状态,并在服务器上将该状态转换为实体状态,然后再保存实体。
从详细答案中查看我的答案here。
希望有所帮助。