2010-01-29 129 views
4

我刚刚开始使用实体框架1.0,并相信我开始感受到每个人都在谈论的痛苦。我试图使用最佳实践,所以我有一组通过AutoMapper映射到我的实体的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; 
     } 

然后我算了一下,也许我只是需要抓住从数据库中的实体第一,重视的背景下,调用地图的方法上映射,然后调用的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属性设置为忽略,但这看起来很sl。。此外,我不确定此时创建的映射是否会停滞。如果它覆盖允许DTO将值映射到实体上的EntityKey的初始设置,那将会以完全不同的方式反弹。

任何人有更好的主意吗?

回答

6

AutoMapper

你的第一个问题是,据我所知AutoMapper没有设计从DTO->实体只有实体 - > DTO去。这可能最近已经改变,所以我不太确定。请参阅此链接什么automapper的目的是做的更多信息:The case for two way mapping

PK映射

你说:“就在这个方法制图规则和设置的EntityKey & VideoID的属性被忽略,但似乎很sl“”

我不认为这是马虎。在持久化之后,你确实不应该碰到一个EntityKey/PK,并且可能应该以某种方式编写它的静态。

实体框架

“现在,我们得到的不是被允许更改属性,VideoID的,因为它使用的视频实体。可爱的财产的EntityKey可爱的EF问题。”

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

+0

jfar:谢谢你的回应。首先,AFAIK AutoMapper是指什么?我在这里指的是AutoMapper:http://code.google.com/p/automapperhome/。关于PK Mapping,我正在讨论在一个地方定义所有的映射,而不是在整个代码中用.CreateMap语句抛出我的代码。这里的问题是我需要以不同的方式将我的DTO映射到我的实体,具体取决于我在数据库中创建新记录还是更新数据库中的记录。更多关于AutoMapper本身的第二个消息......用完字符...... – jason 2010-02-01 19:25:29

+1

好的,您提到Automapper并非打算从DTO - > EF实体,而是打算成为EF - > DTO。如果是这样的话,当我的视图和控制器中使用的对象是DTO对象时,我应该如何通过EF对象更新数据库?我并不想要居高临下或什么。我只是想找出正确的方式来处理插入和更新,而不是将我的应用程序绑定到特定的数据访问实现。我愿意接受你可能提出的任何建议。 – jason 2010-02-01 19:40:49

+0

AFAIK =据我所知,对不起没有更清楚 – jfar 2010-02-01 20:31:10

0

我处于相同的情况。 我得到的唯一解决方案是忽略DTO - > Entity映射中的PK字段。

这样的规则可以通过下面的代码行Automapper配置过程来实现:据我所知

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

,得到EF的唯一途径可与分离的实体被映射DTO到实体您在SaveChanges之前从数据库获取(如您在示例中所做的那样)。

1

这可能会帮助,如果你想避免把.Ignore() S于要映射每个实体。

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?)中的一个属性告诉你这个)。

0

请注意,“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并且映射将不起作用。