ASP.NET MVC / EF4 / POCO / Репозиторий – как обновить отношения?

У меня есть 1 .. * взаимосвязь между обзором и рекомендациями .

Соответствующая часть моей модели (которая также является POCO, отображаемой EF4):

public class Review { public ICollection Recommendations { get; set; } } 

В Edit View я представляю Рекомендации как набор флажков.

Когда я пытаюсь добавить новую Рекомендацию в качестве части редактирования обзора (например, отметьте другое поле), ничего не происходит – и я знаю, почему …

Я использую «метод заглушки» для обновления моих объектов – например, я создаю объект с тем же ключом, прикрепляю его к графику, а затем ApplyCurrentValues . Но это работает только для скалярных свойств, а не для навигационных свойств.

Я нашел этот вопрос StackOverflow, который выглядит хорошо, но я пытаюсь понять, как заставить это работать с POCO / Repository (и ASP.NET MVC – отстраненный контекст).

Поскольку я использую POCO, review.Recommendations является ICollection , поэтому я не могу сделать review.Recommendations.Attach . review.Recommendations.Attach . Я тоже не использую Self-Tracking Entities, поэтому мне нужно вручную работать с отслеживанием графика / изменения, что до сих пор не было проблемой.

Таким образом, вы можете визуализировать сценарий:

Обзор:

  • Рекомендации ( ICollection ):
    • РекомендацияОдин ( Recommendation )
    • Рекомендация 2 ( Recommendation )

Если im в режиме редактирования, два флажка уже отмечены. Третий (представляющий рекомендациюThree) не установлен .

Но если я проверю этот флажок, указанная выше модель станет:

Обзор:

  • Рекомендации ( ICollection ):
    • РекомендацияОдин ( Recommendation )
    • Рекомендация 2 ( Recommendation )
    • РекомендацияТри ( Recommendation )

И поэтому мне нужно привязать RecommendationThree к графику как новый объект .

Нужны ли мне скрытые поля для сравнения опубликованных данных с существующим объектом? Или я должен сохранить объект в TempData и сравнить его с размещенным объектом?

РЕДАКТИРОВАТЬ

Чтобы избежать путаницы, вот полный вызов стека приложений:

ReviewController

 [HttpPost] public ActionResult Edit(Review review) { _service.Update(review); // UserContentService _unitOfWork.Commit(); } 

UserContentService

 public void Update(TPost post) where TPost : Post, new() { _repository.Update(post); // GenericRepository } 

GenericRepository – используется как GenericRepository

 public void Update(T2 entity) where T2 : class, new() { // create stub entity based on entity key, attach to graph. // override scalar values CurrentContext.ApplyCurrentValues(CurrentEntitySet, entity); } 

Поэтому для каждой рекомендации необходимо вызывать методы Update (или Add или Delete ) репозитория, в зависимости от того, что он новый / изменен / удален.

    Возможно, мне нужен больше контекста, но что не так:

     recommendations.Add(newRecomendation) 

    ?

    В ответ на комментарий:

    Хорошо, так что не так с

     SomeServiceOrRepository.AddNewRecommendation( newRecommendation ) 

    или

     SomeServiceOrRepository.AddNewRecommendation( int parentId, newRecommendation ) 

    Последнее предложение? Вы имеете в виду два вопроса?

    Это не должно быть сложно.

    Подводя итог моему ответу, я думаю, что вы делаете «трудный путь» и на самом деле должны сосредоточиться на публикации значений форм, которые соответствуют действию CRUD, которое вы пытаетесь выполнить.

    Если новый объект может появиться одновременно с вашими редактируемыми объектами, вы должны действительно префикс их по-разному, чтобы привязка к нему могла подхватить его. Даже если у вас есть несколько новых элементов, вы можете использовать тот же синтаксис [0], чтобы префикс поля «name» с New или что-то еще.

    Много раз в этом сценарии вы не можете полагаться на функции графа Entity Frameworks, поскольку удаление объекта из коллекции никогда не означает, что оно должно быть установлено для удаления.

    Если форма неизменна, вы также можете попробовать использовать функцию обобщенного присоединения объекта ObjectSet:

     theContect.ObjectSet().Attach( review ) 

    Тонны путей из этого. Может быть, вы можете опубликовать свой controller и просмотреть код?

    Я принял ответ @ jfar, потому что он поставил меня на правильный путь, но подумал, что добавлю ответ здесь для других людей.

    Причина, по которой отношения не обновлялись, объясняется следующими причинами:

    1) Полностью отключенный сценарий. ASP.NET = без гражданства, новый контекст обновил каждый HTTP-запрос.

    2) Отредактированный объект, созданный MVC (привязка к модели), но не существующий в графе.

    3) При использовании POCO без отслеживания изменений выполнение. .Attach к сущности добавит его в график, но сущность и любые дочерние отношения не будут изменены.

    4) Я использую трюк-заглушку и ApplyCurrentValues для обновления объекта, но это работает только для скалярных свойств, а не для навигационных.

    Итак – для того, чтобы заставить выше работать, я должен был бы явно установить EntityState для объекта (что происходит автоматически из-за ApplyCurrentValues ), а также навигационных свойств.

    И есть проблема – как узнать, добавлено / изменено / удалено навигационное свойство? У меня нет объекта для сравнения – только «сущность», которую я знаю, была «отредактирована», но я не знаю, что было отредактировано.

    Таким образом, решение в итоге было следующим:

     [HttpPost] public ActionResult Edit(Review review) { var existingReview = _service.FindById(review.Id); // review is now in graph. TryUpdateModel(existingReview); // MVC equivalent of "ApplyCurrentValues" - but works for ALL properties - including navigationals _unitOfWork.Commit(); // save changed } 

    Вот и все. Мне даже не нужен мой метод _service.Update – поскольку мне больше не нужен трюк-заглушка, потому что обзор находится на графике с извлечением, а ApplyCurrentValues заменяется TryUpdateModel .

    Теперь, конечно, это не решение с параллельным контролем .

    Если я загружу View View View, и до того, как я нажму «Отправить», кто-то изменит Обзор, мои изменения могут быть потеряны.

    К счастью, у меня режим параллелизма «в последний раз», поэтому для меня это не проблема.

    Я люблю POCO, но человек – это боль, когда у вас есть комбинация безгражданности (MVC) и никакого отслеживания изменений.

    Работа с графиками отдельных объектов – мой любимый недостаток EF. Просто боль в заднице. Сначала вам приходится иметь дело с этим самостоятельно. EF вам не поможет. Это означает, что помимо Review вы также должны отправить некоторую информацию о внесенных изменениях. Когда вы присоединяете Review к контексту, он устанавливает Review всех Recommendation и всех отношений в состояние Unchanged . ApplyCurrentValues работает только для скалярных значений, как вы уже нашли. Поэтому вы должны использовать свою дополнительную информацию о внесенных изменениях и установить отношение отношений к Added с помощью ObjectContext.ObjectStateManager.ChangeRelationshipState .

    Я лично отказался от этого подхода, и я загружаю графа объектов из БД, сначала объединяя свои изменения с прикрепленным графом и сохраняю его.

    Я ответил на подобный вопрос более глубоко .

    Давайте будем гением компьютера.