entity framework,AutoMapper,处理实体更新

我最近刚开始使用Entity Framework 1.0,并相信我开始感受到每个人都在谈论的痛苦。 我正在尝试使用最佳实践,因此我有一组DTO通过AutoMapper映射到我的实体和从我的实体映射。

真正的问题是当我试图更新一个对象时。 第一个问题是我找不到创建新实体的方法,从我的DTO传输数据,并且仍然让实体ObjectContext意识到它已被更改。 我使用了以下代码:

public VideoDTO UpdateVideo(VideoDTO pVideo) { Video video = new Video(); Mapper.Map(pVideo, video); context.Attach(video); //Successfully attaches context.ApplyPropertyChanges("Videos", video); // no changes made as far as entity knows b/c it was attached in it's updated state context.SaveChanges(); //doesn't save the entity return pVideo; } 

然后我想,也许我需要先从数据库中获取实体,附加到上下文,在Mapper上调用Map方法,然后调用SaveChanges。 我在这做了什么:

  public VideoDTO UpdateVideo(VideoDTO pVideo) { Video video = context.Videos.Where(v => v.VideoId == pVideo.VideoId).FirstOrDefault(); Mapper.Map(pVideo, video); //Error here: Can't change VideoId value on Video entity //context.Attach(video); //context.ApplyPropertyChanges("Videos", video); context.SaveChanges(); return pVideo; } 

现在我们得到了不允许更改属性VideoId的可爱的EF问题,因为它被Video实体上的EntityKey属性使用。 可爱。 我设置了映射,以便当我从我的DTO映射到EF实体时,EntityKey属性将获得一个值。 现在我需要一种方法来对该映射规则进行例外处理,但不知道从哪里开始。 我想我可以在这个方法中创建一个全新的映射规则,并将EntityKey和VideoId属性设置为忽略,但这看起来非常草率。 此外,我不确定此时创建的映射是否会成功。 如果它覆盖允许DTO将值映射到实体上的EntityKey的初始设置,那将以完全不同的方式适得其反。

谁有更好的主意?

AutoMapper

你的第一个问题是,据我所知,AutoMapper的设计并非来自DTO-> Entity only Entity-> DTO。 这可能最近有所改变,所以我不太确定。 有关automapper旨在执行的操作的详细信息,请参阅此链接: 双向映射的情况

PK映射

你说:“在这个方法中映射规则并设置EntityKey和VideoId属性被忽略,但这看起来很草率”

我认为这根本不是很邋。 你真的不应该在持久化之后触摸EntityKey / PK,并且可能应该以某种方式编写其静态性。

entity framework

“现在我们得到了不允许更改属性VideoId的可爱的EF问题,因为它被video实体上的EntityKey属性使用。很可爱。”

可爱? EF不会强迫您不更新PK。 在生成的模型内部,您的密钥的setter内部会进行属性更改检查。 解决方案是更改生成的代码。 根据您的模型波动性,这可能不实用,但它是一种选择。

尝试映射到现有对象:

 entity = Mapper.Map(dto, entity); 

并将Ignore()保持在原位。

http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1

如果您想避免在要映射的每个实体上放置.Ignore()这可能会有所帮助。

http://www.prosoftnearshore.com/blog/post/2012/03/14/Using-AutoMapper-to-update-Entity-Framework-properties.aspx

实质上,您要将AutoMapper配置为忽略所有非标量的实体属性:

 AutoMapper.Mapper.CreateMap() .ForAllMembers(o => { o.Condition(ctx => { var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping if (!members.Any()) return false; return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set }); }); 

如果属性是PK( EdmScalarPropertyAttribute实例中的属性( EntityKey == true? )告诉你),也许可以添加一些额外的工作来避免重置。

我在同一场景中。 我得到的唯一解决方案是忽略来自DTO – > Entity的映射中的PK字段。

在Automapper配置期间,可以通过以下代码行来实现此类规则:

  Mapper.CreateMap().ForMember("EntityPK",r=>r.Ignore()); 

据我所知,让EF与Detached Entities一起工作的唯一方法是将DTO映射到SaveChanges之前从DB获得的实体(如示例中所示)。

请注意,“Mauricio Morales”提供的示例仅在您不使用前缀时才有效。 如果您使用它们,那么您需要以更多或更少的方式稍微更改上面的代码:

  Mapper.CreateMap() .ForMember(m => m.OR_ID, exp => exp.Ignore()) .ForMember(m => m.OR_CU_ID, exp => exp.Ignore()) .ForAllMembers(o => o.Condition(ctx => { var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping if (!members.Any()) { members = ctx.Parent.SourceType.GetMember("temp" + ctx.MemberName); if (!members.Any()) return false; } return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set })); 

也就是说,您需要在if (!members.Any())语句中包含其他检查。 如果没有这个,函数返回false并且映射将不起作用。