具有 MVC 和修改后的嵌套实体的 Automapper - 如何更新它们
Automapper with MVC and modified nested entities - how to update them
我正在使用 automapper 将我的实体映射到视图模型,并在从视图返回的过程中将视图模型返回到实体。
我有一个小问题,我修改的对象中有一个嵌套的实体列表,可以在视图中修改。当我保存主要对象时,即使所有内容似乎都正确映射到其嵌套实体中,嵌套实体也不会更新(在控制台中看不到与它们相关的 SQL 语句)。
我很确定我想念一些东西来确保 EF 知道它们已被修改。
我发现的唯一一件事就是通知框架我的控制器中的实体已被修改(即使不是全部):
Database.Entry(character).State = EntityState.Modified;
foreach(CharacterAbilityScore cab in character.CharacterAbilityScores)
Database.Entry(cab).State = EntityState.Modified;
如果我没记错的话,当我在我的视图中使用实体而不是 ViewModel 时,我不需要通知 EF 嵌套实体已被修改,它知道并相应地更新数据库。
我只是想确保我有正确的方法。
如果您需要更多代码,请告诉我!
更新:
这是我配置自动映射器的方式:
Mapper.CreateMap<CharacterViewModel, Character>()
.ForMember(dest => dest.CharacterAbilityScores, opt => opt.MapFrom(src => src.CharacterAbilityScoresDTO));
最后更新,答案:
由于我处于 MVC 模式,并且当我们从视图上的 post 返回时重新创建上下文,我必须手动管理我的子实体的更改方式,或者使用自跟踪实体或者像我一样,在我知道它们可能被修改时将它们标记为已修改。不过,这会导致比必要的更新多一点。
您需要独立于您的主要实体来映射您的 collection。否则,AutoMapper 会将整个 collection 替换为映射的 类,而不是将新值实际映射到现有项上。
在您的配置中,告诉 AutoMapper 在映射时忽略您的 collection:
AutoMapper.Mapper.CreateMap<CharacterViewModel, Character>()
.ForMember(dest => dest.CharacterAbilityScores, opts => opts.Ignore());
然后,在您的操作中分两步映射发布的数据:
AutoMapper.Mapper.Map(model, character);
foreach (var item in model.CharacterAbilityScores)
{
var existingItem = character.CharacterAbilityScores.SingleOrDefault(m => m.Id == item.Id);
if (existingItem == null)
{
character.CharacterAbilityScores.Add(AutoMapper.Mapper.Map<CharacterAbilityScore>(item));
}
else
{
AutoMapper.Mapper.Map(item, existingItem);
}
}
由于我处于 MVC 模式,当我从视图上的 post 返回时重新创建上下文,Entity Framework 只能跟踪父对象,不能跟踪嵌套对象。
所以我必须手动管理我的子实体如何更改,无论是使用自我跟踪实体还是像我一样,在我知道它们可能会被修改时将它们标记为已修改。不过,这会导致比必要的更新多一些。
因此,要么使用自我跟踪实体(请参阅此博客 post)http://blog.tonysneed.com/2013/11/18/trackable-entities-versus-self-tracking-entities/,要么像我在原始问题中所做的那样将它们标记为 "modified"(这会导致更多更新比必要的,如果仍然少量是可以接受的)。
我正在使用 automapper 将我的实体映射到视图模型,并在从视图返回的过程中将视图模型返回到实体。
我有一个小问题,我修改的对象中有一个嵌套的实体列表,可以在视图中修改。当我保存主要对象时,即使所有内容似乎都正确映射到其嵌套实体中,嵌套实体也不会更新(在控制台中看不到与它们相关的 SQL 语句)。
我很确定我想念一些东西来确保 EF 知道它们已被修改。
我发现的唯一一件事就是通知框架我的控制器中的实体已被修改(即使不是全部):
Database.Entry(character).State = EntityState.Modified;
foreach(CharacterAbilityScore cab in character.CharacterAbilityScores)
Database.Entry(cab).State = EntityState.Modified;
如果我没记错的话,当我在我的视图中使用实体而不是 ViewModel 时,我不需要通知 EF 嵌套实体已被修改,它知道并相应地更新数据库。
我只是想确保我有正确的方法。
如果您需要更多代码,请告诉我!
更新:
这是我配置自动映射器的方式:
Mapper.CreateMap<CharacterViewModel, Character>()
.ForMember(dest => dest.CharacterAbilityScores, opt => opt.MapFrom(src => src.CharacterAbilityScoresDTO));
最后更新,答案:
由于我处于 MVC 模式,并且当我们从视图上的 post 返回时重新创建上下文,我必须手动管理我的子实体的更改方式,或者使用自跟踪实体或者像我一样,在我知道它们可能被修改时将它们标记为已修改。不过,这会导致比必要的更新多一点。
您需要独立于您的主要实体来映射您的 collection。否则,AutoMapper 会将整个 collection 替换为映射的 类,而不是将新值实际映射到现有项上。
在您的配置中,告诉 AutoMapper 在映射时忽略您的 collection:
AutoMapper.Mapper.CreateMap<CharacterViewModel, Character>()
.ForMember(dest => dest.CharacterAbilityScores, opts => opts.Ignore());
然后,在您的操作中分两步映射发布的数据:
AutoMapper.Mapper.Map(model, character);
foreach (var item in model.CharacterAbilityScores)
{
var existingItem = character.CharacterAbilityScores.SingleOrDefault(m => m.Id == item.Id);
if (existingItem == null)
{
character.CharacterAbilityScores.Add(AutoMapper.Mapper.Map<CharacterAbilityScore>(item));
}
else
{
AutoMapper.Mapper.Map(item, existingItem);
}
}
由于我处于 MVC 模式,当我从视图上的 post 返回时重新创建上下文,Entity Framework 只能跟踪父对象,不能跟踪嵌套对象。
所以我必须手动管理我的子实体如何更改,无论是使用自我跟踪实体还是像我一样,在我知道它们可能会被修改时将它们标记为已修改。不过,这会导致比必要的更新多一些。
因此,要么使用自我跟踪实体(请参阅此博客 post)http://blog.tonysneed.com/2013/11/18/trackable-entities-versus-self-tracking-entities/,要么像我在原始问题中所做的那样将它们标记为 "modified"(这会导致更多更新比必要的,如果仍然少量是可以接受的)。