2013年4月5日 星期五

使用 AutoMapper 處理類別之間的對映轉換

以往使用傳統 ADO.NET 方式對資料庫存取資料時都會碰上資料對映的處理,這是指已經在系統中使用物件導向開發的情況(而沒有使用物件導向的程式中大多是不會遇到這個問題),當從資料庫取得資料後為了要對映到我們所定義的類別,如果沒有使用輔助方法的話,很多人都是乖乖地在程式中去將一筆筆的資料做迴圈處理,然後再一個欄位對映到類別指定的屬性,因為這樣一筆一筆地對映實在太花時間了,所以就有很多輔助方法的產生,有些人會自己寫,而我則是使用 Enterprise Library Data Access Application Block 裡的 RowMapper 方法,在我之前的文章也曾經介紹過,如下:

簡述 Oracle + Enterprise Library 5.0 Data Access Application Block 的操作
Entity Framework 與 Stored Procedure - 回傳多種資料集

而 Microsoft MVP - 91 也曾經發表了他所設計的 RowMapper 模組「[.NET]RowMapper模組」「[.NET]透過 T4 產生對應 DB table 的 entity」,都是用在資料與類別對映的處理上。

而到了完全以物件導向開發的時候,尤其是已經在專案中使用 ORM Solution,如:ADO.NET Entity Framework or nHibernate 等,大多都是資料庫的 Table 對映到專案的類別,這一段的對映處理不必由我們動手做,在大部分的專案開發上都是一個類別用到底,但有些專案開發時會因為需求而產生了 一些類別,這些類別的屬性可能來自不同的原生類別,而在 ASP.NET MVC 裡最常碰到的就是 ViewModel 類別,而處理這些類別的對映,又遇到上面我所描述過的狀況,如果沒有使用輔助方法的話,又需要一筆一筆資料去做對映,但只少比一般 ADO.NET 的對映處理已經是方便許多,而 AutoMapper 就是可以幫我們簡化這種類別之間的對映轉換處理,讓程式在處理時可以更加簡易也可以更加優雅些,也可以省下更多的開發時間;接著就來讓我簡單介紹怎麼使用 AutoMapper。

 


先來看看之前文章所遇到的狀況,可以先看「Entity Framework 與 Stored Procedure - 基本的 Select」做個了解,在那篇文章裡是使用 EF 執行 Stored Procedure 然後取得資料,而所取得的資料是 Customer 資料,取回的是全部的欄位,但是執行 Stored Procedure 所取得的資料在最後由 EF 所回傳後的物件類別並不是預設 Entity Framework 對映 Table 所產生的類別,而是「ObjectResult<T>」,如下:

image

在 CustomerController 需要去面對兩個結構大致相同的類別,如果後續要處理這種資料類別轉換的情況越來越多,那麼 CustomerController 就會需要面對很多的類別,而這些類別的結構彼此又有很多雷同,那個混亂的情況也就會越來越多。

其實可以把這個可能發生的情形給單純化,那就是在 CustomerController 所要處理的類別只有一種「Customer」,而至於那些由 EF 去執行 Stored Procedure 所產生的 ObjectResult<T> 就當做是一種 DTO(Data Transfer Object),只是用來傳輸資料而已,不需要拿到流程控制或是商業邏輯處理中。

但如果像我所說的要把 ObjectResult<T> 轉換成指定類別時,最常見的作法:

image

如果欄位少的話是還好,如果欄位數量多的話,這樣的處理光是想就很累人,有些開發人員就會使用 Reflection 去寫個專門處理這個類別對映轉換的方法, 不過我會優先考慮使用 AutoMapper 來做這樣的處理。

 


AutoMapper

http://automapper.org/
https://github.com/AutoMapper/AutoMapper

image

 

安裝

我們在 Visual Studio 裡透過 NuGet 安裝 AutoMapper 到專案中,

SNAGHTML1a1dbc6

 

使用

我們把剛剛的那個手動對映的程式改用 AutoMapper 來處理,首先要先建立好怎麼對映,

image

然後再使用 Map() 方法執行對映,

image

完成的程式內容,

image

與之前的手動對映做個比較,兩者比較之下就知道差別了,

image

下個中斷點做個觀察,可以看到資料都有對映,除了關連屬性,

image

 

設定忽略屬性對映

以上面的例子,建立對映是使用預設處理,會由 AutoMapper 去判斷 Source 類別與 Destination 類別的屬性然後去做對映,這通常是會用在兩個結構一致的情況,有的時候會有些屬性是不必去做對映處理,例如 usp_GetAllCustomerResult 就沒有 Customer 的 CustomerDemographics 與 Orders 屬性,所以我們可以設定忽略這兩個數性的對映處理,

image

 

自定對映格式化

如果現在 usp_GetAllMember_Result 要做對映轉換的類別不是 Customer 而是另一個自定類別時,例如一個 ViewModel,

image

其中有些屬性是需要做字串組合的,例如 ContactData 是 ContactName + ContactTitle,FullAddress 是 Country + City + PostalCode + Address,那麼我們可以在建立對映的時侯使用 ForMember() 方法去對對映的值做處理,

image

執行結果

image

image

 


這一篇就先介紹到這裡,從簡單的設定以進階一點的設定來入門,AutoMapper 在 ASP.NET MVC 的應用中最常拿來用在 ViewModel 的對映上,也的確簡化了設定以及編輯程式的時間,同時也可以藉由設定來統一管理 Entity Model 與 ViewModel 的對映,減少各種對映的散亂,所以下一篇就來說明有關 Configuration 的部份。

 

以上

6 則留言:

  1. Kevin您好:
    想請教,目前進行MVC開發,實作上是有做Model 與 edmx 的建立,再使用Mapper.CreateMap 建立類別轉換的設定,是OK的
    想了解下,如果專案是以Code First的方式,這樣有需要再使用AutoMapper嗎??
    若理解有誤,再不吝指教

    回覆刪除
    回覆
    1. 你好,使用情境上並沒有做什麼樣的預期限定,
      之所以會做類別的對應轉換,就是因為使用情境的不同,
      有的地方需要顯示的資料只有一部分,
      有些地方需要的資料會需要多個類別的資料來做組合,
      而 Code First 與 Database First 或是 Model First 其實都是一樣的,
      最明顯的地方就在於 Entity 類別與 ViewModel 類別的轉換,
      Code First 所建立的 Model 也跟 Database First 所建立的類別是一樣的。

      今天不用 Entity Framework 而改用 NHibernate 或是 Dapper 還是使用傳統的 ADO.NET,
      基礎的類別在很多地方並不是只有使用單一類別就可以完成操作或顯示,
      以頁面顯示來說,有時候一個頁面會顯示多個類別裡多個屬性的資料,
      這時候會建立另一個功能性的類別,我們稱為 ViewModel 或是 DTO,這個類別的屬性是來自多個基礎類別,
      那麼當我們要把資料塞到這個 ViewModel 的時候,如果還是一個屬性對應一個屬性的操作,那麼就會很累人,
      所以可以使用 AutoMapper 來幫我們做這樣的處理,
      使用上並不是說是不是使用了哪一種技術或是方式就可以不必使用 AutoMapper 或是就得用 AutoMapper,
      而是要看使用情境與當下的狀況。

      刪除
    2. Kevin好:感謝您的解答,有比較清楚的理解了!!!

      刪除
  2. 剛找到的應該是官方說明文件 https://github.com/AutoMapper/AutoMapper/wiki

    回覆刪除
  3. 作者已經移除這則留言。

    回覆刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。