Действие PUT на контроллере WebApi не сохраняет данные в базу данных

У меня очень простой проект 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, кажется, выполняется, но база данных не предполагает, что он имеет.

Вот строки get и put json из метода PUT согласно Fiddler2:

получить JSONположить JSON

Примечание: у меня есть эти строки кода в моем файле Global.asax, так что Json правильно обрабатывает модели:

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

Я надеюсь, что кто-то может увидеть, где я иду не так. Любая помощь будет принята с благодарностью.

Заранее спасибо,

Павел.

1 ответ

Решение

Посмотрите на 2 строки кода:

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

Ваша проблема заключается в том, что, поскольку у вас есть родительская сущность с дочерней сущностью, вы устанавливаете состояние сущности родительской функции как измененное, но на самом деле то, что изменилось, было дочерней сущностью, поэтому вы оставили состояние сущности дочернего объекта как неизменное (платформа Entity действительно применяет измененное состояние для одной сущности, не похожее на "Добавлено", которое будет применено ко всему графику), поэтому на стороне сервера, если вы просто установите состояние сущности спецификации как измененное, вы внесете свои изменения в базу данных.

Теперь то, что я предложил, не является постоянным решением, но это просто, чтобы показать вам вашу проблему и как решить ее временно.

Чтобы решить эту проблему навсегда и поскольку ваш клиент представляет собой отключенный граф, вашему клиенту необходимо отслеживать объекты и нести ответственность за то, что произошло с объектами графа (добавлены, изменены, удалены или не изменены).

Вам необходимо реализовать интерфейс, такой как IObjectState, и позволить вашим клиентам изменять состояние отключенного графа, и на сервере вы преобразуете это состояние в состояние объекта, прежде чем сохранить объект.

Посмотрите на мой ответ здесь из подробного ответа.

Надеюсь, это поможет.

Другие вопросы по тегам