Это длинный.
Итак, у меня есть модель и модель просмотра, которую я обновляю из запроса AJAX. Контроллер Web API получает модель просмотра, которая затем обновляет существующую модель с помощью AutoMapper, как показано ниже:
private User updateUser(UserViewModel entityVm)
{
User existingEntity = db.Users.Find(entityVm.Id);
db.Entry(existingEntity).Collection(x => x.UserPreferences).Load();
Mapper.Map<UserViewModel, User>(entityVm, existingEntity);
db.Entry(existingEntity).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch
{
throw new DbUpdateException();
}
return existingEntity;
}
У меня есть automapper, настроенный так для отображения User → UserViewModel (и обратно).
Mapper.CreateMap<User, UserViewModel>().ReverseMap();
(Обратите внимание, что явно задание противоположного отображения и исключение ReverseMap проявляет то же поведение)
У меня возникла проблема с членом Model/ViewModel, который является ICollection другого объекта:
[DataContract]
public class UserViewModel
{
...
[DataMember]
public virtual ICollection<UserPreferenceViewModel> UserPreferences { get; set; }
}
Соответствующая модель такова:
public class User
{
...
public virtual ICollection<UserPreference> UserPreferences { get; set; }
}
Проблема:
Каждое свойство классов User и UserViewModel корректно отображает, за исключением ICollections
UserPreferences/UserPreferenceViewModels, показанного выше. Когда эти коллекции отображаются из ViewModel в Model, а не из свойств карты, новый экземпляр объекта UserPreference создается из ViewModel, а не обновляет существующий объект с помощью свойств ViewModel.
Модель:
public class UserPreference
{
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
[ForeignKey("CreatedBy")]
public int? CreatedBy_Id { get; set; }
public User CreatedBy { get; set; }
[ForeignKey("User")]
public int User_Id { get; set; }
public User User { get; set; }
[MaxLength(50)]
public string Key { get; set; }
public string Value { get; set; }
}
И соответствующий ViewModel
public class UserPreferenceViewModel
{
[DataMember]
public int Id { get; set; }
[DataMember]
[MaxLength(50)]
public string Key { get; set; }
[DataMember]
public string Value { get; set; }
}
И конфигурация automapper:
Mapper.CreateMap<UserPreference, UserPreferenceViewModel>().ReverseMap();
//also tried explicitly stating map with ignore attributes like so(to no avail):
Mapper.CreateMap<UserPreferenceViewModel, UserPreference>().ForMember(dest => dest.DateCreated, opts => opts.Ignore());
При сопоставлении объекта UserViewModel с пользователем ICollection of UserPreferenceViewModels также отображает пользовательский ICollection UserPreferences, как и следовало ожидать.
Однако, когда это происходит, отдельные свойства объекта UserPreference, такие как "DateCreated", "CreatedBy_Id" и "User_Id", обнуляются, как будто создается новый объект, а не отдельные копии, которые копируются.
Это также показано в качестве доказательства того, что при сопоставлении UserViewModel, который имеет только 1 объект UserPreference в коллекции, при проверке DbContext после оператора карты есть два локальных объекта UserPreference. Тот, который выглядит как новый объект, созданный с помощью ViewModel, и тот, который является оригиналом существующей модели.
Как я могу заставить automapper обновлять существующие элементы коллекции Model, а не создавать экземпляры новых членов из коллекции ViewModel? Что я здесь делаю неправильно?
Скриншоты для демонстрации до/после Mapper.Map()