代码之家  ›  专栏  ›  技术社区  ›  jason

实体框架,automapper,处理实体更新

  •  4
  • jason  · 技术社区  · 16 年前

    我最近刚开始使用实体框架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;
            }
    

    然后我想,也许我需要先从数据库中获取实体,附加到上下文,在映射器上调用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问题,因为它被视频实体上的entitykey属性使用。很可爱。我设置了映射,这样当我从DTO映射到EF实体时,EntityKey属性将得到一个值。现在,我需要一种方法来对该映射规则进行例外处理,但不知道从哪里开始。我想我可以在这个方法中创建一个全新的映射规则,并将EntityKey&videoID属性设置为被忽略,但这看起来相当草率。此外,我不确定在这一点上创建的映射是否会保持不变。如果它超越了允许DTO将值映射到实体上EntityKey的初始设置,则会以完全不同的方式产生相反的效果。

    有人有更好的主意吗?

    5 回复  |  直到 13 年前
        1
  •  6
  •   John Farrell    16 年前

    自动装订机

    您的第一个问题是,据我所知,automapper不是设计为从DTO转到实体专用实体DTO。这可能最近发生了变化,所以我不太确定。有关automapper的设计目的的详细信息,请参阅此链接: The case for two way mapping

    PK映射

    您会说:“在该方法中映射规则,并将EntityKey&videoID属性设置为忽略,但这似乎相当草率。”

    我觉得这一点都不马虎。在实体键/pk被持久化之后,您真的不应该触摸它,可能应该以某种方式将其静态化。

    实体框架

    “现在我们讨论了不允许更改属性videoid的可爱的ef问题,因为它被视频实体上的entitykey属性使用。很可爱。”

    可爱吗?英孚没有强迫你不更新你的pk。在生成的模型中,在setter中对您的键进行属性更改检查。解决方案是更改生成的代码。取决于您的模型波动性,这可能不实际,但它是一个选项。

        2
  •  3
  •   ishakkulekci    14 年前

    尝试映射到现有对象:

    entity = Mapper.Map<MyDTO, NyEntity>(dto, entity); 
    

    保持ignore()的位置。

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

        3
  •  1
  •   Mauricio Morales    14 年前

    如果你想避免 .Ignore() 在您要映射的每个实体上。

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

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

    AutoMapper.Mapper.CreateMap<EntityType, EntityType>()
        .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? )告诉你这个)。

        4
  •  0
  •   Bitbreaker    16 年前

    我也有同样的想法。 我得到的唯一解决方案是忽略dto->实体映射中的pk字段。

    这种规则可以在automaper配置期间通过以下代码行实现:

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

    据我所知,让ef处理分离实体的唯一方法是将dto映射到保存更改之前从db获得的实体(如示例中所做的)。

        5
  •  0
  •   Chris Laplante    13 年前

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

        Mapper.CreateMap<tempOR_Order, OR_Order>()
            .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,映射将不起作用。