2012-10-31 239 views
7

我有一個具有以下結構的實體框架POCO。使用Automapper將DTO映射到實體

public class Entity 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
} 

我創建了一個數據傳輸對象,供我的視圖使用該實體。

public class EntityDto 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

現在,我的Global.asax文件中有以下映射代碼。

Mapper.CreateMap<Entity, EntityDto>(); 
Mapper.CreateMap<EntityDto, Entity>(); // not sure whether I need this as well? 

一切工作正常,我通過DTO我的意見確定,我可以從我EntityDto模型創建的Entity一個新的實例。當我嘗試編輯我的Entity時出現問題;我意識到這是AutoMapper失去EF創建的實體關鍵字來跟蹤對象的變化,但通過幾個來源閱讀,似乎並沒有一個明確的解決方案。這是我用來編輯我的實體的操作。

public ActionResult EditEntity(EntityDto model) 
{ 
    var entity = context.Entities.Single(e => e.Id == model.Id); 
    entity = Mapper.Map<EntityDto, Entity>(model); // this loses the Entity Key stuff 
    context.SaveChanges(); 

    return View(model); 
} 

現在,我該怎麼做才能解決這個問題?我可以:

  1. 不知何故告知AutoMapper的.Ignore()實體密鑰屬性?
  2. 獲取AutoMapper複製實體密鑰屬性?
  3. .Attach()我的地圖Entity並設置狀態爲已修改?

任何幫助總是讚賞。

回答

7

.Attach()我的映射實體並設置狀態爲已修改?

public ActionResult EditEntity(EntityDto model) 
{ 
    var entity = Mapper.Map<Entity>(model); 
    context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);) 
    context.Entry<Entity>(entity).State = System.Data.EntityState.Modified; 
    context.SaveChanges(); 
    return View(model); 
} 

哪裏是你的上下文中實例?你應該在你的EditEntity動作中做到這一點。

public ActionResult EditEntity(EntityDto model) 
{ 
    using(var context = new MyContext()) 
    { 
     var entity = Mapper.Map<Entity>(model); 
     context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);) 
     context.Entry<Entity>(entity).State = System.Data.EntityState.Modified; 
     context.SaveChanges(); 
     return View(model); 
    } 
} 
+0

輝煌,這只是工作。給我一些時間來嘗試我的實際項目。 –

+0

這正是我正在尋找的,再次感謝! –

+0

很高興我可以alt選項卡和複製粘貼..我的意思是幫助你。 :) – Pluc

12

嘗試將實體作爲第二個參數傳遞給您的映射。

entity = Mapper.Map<EntityDto, Entity>(model, entity); 

否則,你的實體實例是覆蓋一個新實例,你失去了在第一行創建的實體。

+0

不幸的是,我已經嘗試過這一點,導致同樣的問題 - 基本上AutoMapper說,它無法找到映射配置,因爲當我從上下文中檢索到我的實體時,它不僅僅是您的普通POCO,所以AutoMapper不會不知道該怎麼做。 –

+0

如果實體上還有其他屬性沒有列出,那麼您可能想告訴AutoMapper忽略它們: .ForMember(dest => dest.PropertyToIgnore,opt => opt.UseDestinationValue) –

+0

這是問題,在創建AutoMapper映射的時候'Entity'只是一個POCO,所以不包含EF在檢索時創建的額外實體內容,所以我不能告訴AutoMapper忽略它們。 –

1

不需要Automapper的DTO到實體轉換的備選答案是使用DbEntry:

 var oldEntity = DbSet.FirstOrDefault(x => x.Id == updatedEntity.Id); 
     var oldEntry = Context.Entry(oldEntity); 

     oldEntry.CurrentValues.SetValues(updatedEntity); 

你不需要任何附加/狀態檢查,因爲你越來越老實體第一,所以它有更改跟蹤附加到它。另外,CurrentValues.SetValues可以接受不同的類型,在這個例子中,updatedEntity是DTO。設置值文檔解釋如下:

通過讀取給定對象的值來設置此字典的值。給定的對象可以是任何類型。將讀取名稱與字典中的屬性名稱匹配且可讀取的對象上的任何屬性。其他屬性將被忽略。這允許例如從簡單數據傳輸對象(DTO)複製屬性。

因此,它似乎已經可以以automapper-esque方式執行。

+0

這完全爲我工作。 Mapper.Map(模型,實體)解決方案對我不起作用,因爲當你有一個嵌套的實體時,你更新了(所以你的屬性現在引用了一個不同的(ALREADY跟蹤的)實體),automapper解決方案將「覆蓋」之前引用的實體,並且更改跟蹤器會抱怨它已經使用該標識符跟蹤實體。 – nicolaas

相關問題