Как правильно PUT сложного типа объекта в MVC Entity Framework
Я отправляю запрос json в мой ProductController через ресурс Angularjs $, используя метод PUT. Продукт успешно получен. Проблема заключается в обновлении сложных свойств продукта. Вот модель продукта.
Product{
//other properties
public virtual List<Bookmark> Bookmarks { get; set; }
public virtual List<ProductCounter> Counters { get; set; }
}
Теперь вот мой метод PUT контроллера.
public HttpResponseMessage PutProduct(int key, Product product)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (key != product.ID)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
product.ProductDocuments.Clear();
var counters = new List<ProductCounter>(product.Counters);
product.Counters.Clear();
foreach (var counter in counters)
{
product.Counters.Add(counter);
db.Entry(counter).State = EntityState.Added;
}
db.Entry(product).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
Если я удаляю блок foreach, все счетчики удаляются.
Если я добавлю блок foreach, если товар содержит какие-либо счетчики, они все дублируются. 2 счетчика в продукте станут 4 и так далее. В чем проблема? даже я клонирую список счетчиков, но не знаю, почему ясно, что без foreach работает, и с очищенными счетчиками foreach возвращаются снова. Даже я пытался установить ID в 0 счетчиков в foreach, но это также дублировало записи.
Я пробовал эту версию foreach after counters.clear();
foreach (var counter in counters)
{
product.Counters.Add(new ProductCounter(){Name=counter.Name,Value=counter.Value});
}
это дает эту ошибку в ответе:
"" innererror ": {" message ":" Произошла ошибка при сохранении сущностей, которые не предоставляют свойства внешнего ключа для своих отношений. Свойство EntityEntries вернет значение NULL, поскольку один объект не может быть определен как источник исключения. Обработка исключений при сохранении может быть упрощена путем предоставления свойств внешнего ключа в типах объектов. Смотрите InnerException для подробностей.
"internalexception": {"message": "Оператор обновления, вставки или удаления магазина затронул неожиданное количество строк (0). Возможно, объекты были изменены или удалены с момента загрузки объектов. Обновить записи ObjectStateManager.","type":"System.Data.Entity.Core.OptimisticConcurrencyException","stacktrace":"в System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(параметры SaveOptions)\r\n в System.Data.Entity.Internal.InternalContext. Сохранить изменения()"
Вот метод POST, для получения дополнительной информации. Счетчики фактически добавляются в продукт заново, а другие сложные свойства, такие как Documents и ProjectTasks, связаны между собой.
// POST api/Product
public HttpResponseMessage PostProduct(Product product)
{
if (ModelState.IsValid)
{
db.Products.Add(product);
foreach (var projectTask in product.ProjectTasks)
{
db.ProjectTasks.Attach(projectTask);
}
foreach (var bookmark in product.Bookmarks)
{
db.Bookmarks.Attach(bookmark);
}
foreach (var document in product.ProductDocuments)
{
db.Documents.Attach(document);
}
//No attachment for counters, they are added as a list. if I remove all attachments for other entities, these entities get duplicated in their own tables.
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, product);
//response.Headers.Location = new Uri(Url.Link("DefaultApi", new { key = product.ID }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
Вопрос: я хочу сохранить только ближайшие счетчики и больше не существующие. Делается ли это через сначала очистку всех, а затем добавление новых пришедших? или любой другой метод?
1 ответ
После ваших savechanges() вы должны использовать. Этот работал для меня
db.Entry(projectTask).State = EntityState.Unchanged;