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

时间:2022-12-02 10:32:21

I have a very simple MVC5 WebApi project with the following models:

我有一个非常简单的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; }
}

Here is the PUT action (the scaffolded action):

这是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);
}

When the code executes db.SaveChanges(); the code executes as expected but the database doesn't get updated.

当代码执行db.SaveChanges();代码按预期执行,但数据库不会更新。

Here is the code in the console application that triggers the PUT request:

以下是控制台应用程序中触发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);
                }
            }
        }

What this method does is get the product requested (1), updates a field in the child (BOM.Counter) by incrementing a value on that field.

此方法的作用是获取所请求的产品(1),通过递增该字段上的值来更新子项中的字段(BOM.Counter)。

It's just that the database does not update so when the application starts again, obviously we're getting the old value and not the updated one. The SaveChanges method seems to execute but the database doesn't suggest that it has.

只是数据库没有更新,所以当应用程序再次启动时,显然我们得到的是旧值而不是更新的值。 SaveChanges方法似乎已执行,但数据库并未建议它具有。

Here are the get and put json strings from the PUT method as per Fiddler2:

根据Fiddler2,这是来自PUT方法的get和put json字符串:

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

Note: I have these lines of code in my Global.asax file so that Json handles the models correctly:

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

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

I'm hoping someone can see where I'm going wrong. Any help would really be appreciated.

我希望有人能看到我出错的地方。真的很感激任何帮助。

Thanks in advance,

提前致谢,

Paul.

1 个解决方案

#1


1  

Look at 2 lines of code:

看看2行代码:

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

Your problem is that because you have a parent entity with a child entity, You are setting the parent's entity state to be Modified but what changed actually was the child entity, so you left the child's entity state to be Unchanged (Entity framework does apply the modified state on single entity not like "Added" which will be applied on the whole graph), so on the server side if you just set the BOM entity state to be Modified, you will get your changes into the database.

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

Now what I suggested is not a permanent solution, but this is just to show you your problem and how to solve it temporary.

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

To solve it permanently and because your client is a disconnected graph, your client needs to track the objects and being responsible of what happened with the graph entities (added, modified, deleted, or unchanged).

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

You need to implement an interface like IObjectState and let your clients change the state of the disconnected graph and on the server you convert that state to the entity state in before you save the entity.

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

Look at my answer here from a detailed answer.

从详细的答案看我的答案。

Hope that helps.

希望有所帮助。

#1


1  

Look at 2 lines of code:

看看2行代码:

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

Your problem is that because you have a parent entity with a child entity, You are setting the parent's entity state to be Modified but what changed actually was the child entity, so you left the child's entity state to be Unchanged (Entity framework does apply the modified state on single entity not like "Added" which will be applied on the whole graph), so on the server side if you just set the BOM entity state to be Modified, you will get your changes into the database.

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

Now what I suggested is not a permanent solution, but this is just to show you your problem and how to solve it temporary.

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

To solve it permanently and because your client is a disconnected graph, your client needs to track the objects and being responsible of what happened with the graph entities (added, modified, deleted, or unchanged).

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

You need to implement an interface like IObjectState and let your clients change the state of the disconnected graph and on the server you convert that state to the entity state in before you save the entity.

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

Look at my answer here from a detailed answer.

从详细的答案看我的答案。

Hope that helps.

希望有所帮助。