【发布时间】:2019-11-13 00:23:31
【问题描述】:
这是一篇很长的文章。
所以,我有一个模型和一个视图模型,我正在从 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;
}
我已经为 User -> UserViewModel(和返回)映射配置了这样的自动映射器。
Mapper.CreateMap<User, UserViewModel>().ReverseMap();
(请注意,显式设置相反的地图并省略 ReverseMap 表现出相同的行为)
我对作为不同对象的 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 类的每个属性都正确映射,但上面显示的 UserPreferences/UserPreferenceViewModels 的 ICollections 除外。当这些集合从 ViewModel 映射到 Model 而不是映射属性时,会从 ViewModel 创建一个 UserPreference 对象的新实例,而不是使用 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; }
}
以及自动映射器配置:
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 实体映射到用户时,UserPreferenceViewModels 的 ICollection 也会映射到 UserPreferences 的用户 ICollection,这也是应该的。
但是,当这种情况发生时,单个 UserPreference 对象的属性(例如“DateCreated”、“CreatedBy_Id”和“User_Id”)会变为空,就像创建了一个新对象而不是复制单个属性一样。
这进一步显示为在映射集合中只有 1 个 UserPreference 对象的 UserViewModel 时,在检查 DbContext 时,在 map 语句之后有两个本地 UserPreference 对象。一个似乎是从 ViewModel 创建的新对象,另一个是现有模型的原始对象。
如何让 automapper 更新现有模型的集合成员,而不是从 ViewModel 的集合中实例化新成员?我在这里做错了什么?
在 Mapper.Map() 之前/之后演示的屏幕截图
【问题讨论】:
-
您可能需要覆盖
UserPreference和UserPreferenceViewModel中的GetHashCode,以便集合可以将它们识别为相同。也许 automapper 有一些魔力,但我很怀疑 -
是的,一定是为 CreateMap 行复制/粘贴了错误的行。我目前正在研究 GetHashCode 覆盖,如果发现任何内容,我会报告。感谢您的帮助。
-
您需要退后一步,停止使用 AutoMapper 从 ViewModel 映射到您的实体或领域模型。 AutoMapper 不是为此而设计的,不会按预期工作。使用 AutoMapper ONLY 从实体/域模型映射到 ViewModel/DTO/BindingModel,NEVER 其他方式。 AutoMapper 作者强烈反对这样做
-
@Tseng,我在哪里可以阅读更多关于此的信息?我以前没有遇到过这种区别。
-
特别是看看这篇帖子 uglybugger.org/software/post/… 和 AutoMapper 作者 Jimmy 的评论:“3) AutoMapper 从来没有打算将 back 映射到行为模型中。 AutoMapper 旨在构建 DTO,而不是映射回"
标签: c# mapping automapper