2010-01-29 128 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並且映射將不起作用。