Web Api Controller上的PUT操作不将数据保存到数据库

时间:2014-12-02 00:37:56

标签: json asp.net-web-api json.net entity-framework-6

我有一个非常简单的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字符串

get json put json

注意: 我在Global.asax文件中有这些代码行,以便Json正确处理模型:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

我希望有人能看到我出错的地方。任何帮助都会非常感激。

提前致谢,

保罗。

1 个答案:

答案 0 :(得分:1)

看两行代码:

  Product product = JsonConvert.DeserializeObject<Product>(json);
  product.BOM.Counter += 1;

你的问题是因为你有一个带有子实体的父实体,你将父实体的状态设置为Modified,但实际上改变的是子实体,所以你让孩子的实体状态保持不变(实体框架)确实将修改后的状态应用于单个实体,而不是像“已添加”那样将应用于整个图形,因此在服务器端,如果您只是将BOM实体状态设置为Modified,您将获得对数据库的更改。 / p>

现在我建议的不是永久解决方案,但这只是为了向您展示您的问题以及如何临时解决。

要永久解决它并且因为您的客户端是断开连接的图形,您的客户端需要跟踪对象并负责图形实体发生的事情(添加,修改,删除或未更改)。

您需要实现类似IObjectState的接口,让您的客户端更改断开连接的图形的状态,并在服务器上将该状态转换为实体状态,然后再保存实体。

从详细答案中查看我的答案here

希望有所帮助。