天天看點

淺入 ABP 系列(7):對象映射

目錄

基礎

DTO和實體

麻煩的映射

AutoMapper 內建

IObjectMapper/ObjectMapper

對象拓展

寫部落格的過程中,發現很多基礎理論太薄弱,是以很多專業詞彙可能會解釋錯誤或者不準确,建議讀者多參考官方文檔或者其它書籍。

本篇主要講解 ABP 中如何配置、使用對象映射,其中大部分跟 AutoMapper 這個架構有關,建議讀者預先學習這個架構,可參考筆者的另一篇部落格:淺入 AutoMapper

實體

實體是領域驅動設計(Domain Driven Design)中的概念,實體通常一一映射某些對象的固有屬性,最常使用的是關系型資料庫中的表。

在 ABP 中,實體位于領域層中,實體類需要實作 <code>IEntity</code> 接口或繼承 <code>Entity</code> 基類,示例如下:

DTO

資料傳輸對象(Data Transfer Object),作為資料傳輸過程中的資料模型,用于在應用層和表示層之間傳輸資料。

在 ABP 中,DTO 位于應用服務層,即本系列文章示例源碼中的 <code>AbpBase.Application</code> 項目。

通常表示層或其它類型的用戶端調用應用服務時,将 DTO 作為參數傳遞,它使用領域對象(實體)執行某些特定的業務邏輯,并将 DTO (跟傳入的 DTO 不是同一個)傳回到表示層中,是以表示層與領域層完全隔離。

DTO 類 可能會跟 實體類的字段/屬性高度相似,為每個服務的每個方法建立 DTO 類可能會很枯燥且費時間。

ABP 的 DTO 類示例如下:

前面提到,領域層和應用服務層是要隔離的,例如以下僞代碼:

這樣每次都需要手動為 DTO 類和 實體類手動對字段指派映射,當一個實體有數十個字段時,寫出的代碼會很冗長,而且容易忽略了某些字段,最終導緻了 Bug。

大家都知道, AutoMapper 正好可以解決這個問題。

ABP 的 <code>Volo.Abp.AutoMapper</code> 子產品封裝或內建了 AutoMapper,是以我們正好使用子產品,為 ABP 應用定義對象映射。

關于 AutoMapper 的使用,如何配置 Profile 等,筆者已經單獨寫到 淺入 AutoMapper,請點選連結另外學習 AutoMapper 的使用。

我們可以在 <code>AbpBase.Application</code>  項目中,建立 一個 <code>AbpBaseApplicationAutoMapperProfile.cs</code> 檔案,這個檔案用于實作 Profile 以及定義映射。将服務領域的映射集中到這個檔案中;或者建立一個 <code>Profiles</code> 檔案夾,在其中存放一些 Profile 類。

其内容如下:

定義完畢後,需要配置 AutoMapper 依賴注入,可在 <code>AbpBaseApplicationModule</code>  的 <code>ConfigureServices</code> 方法中,增加以下代碼:

在 Debug 階段,我們擔心項目改動代碼時,新增的字段忘記了加入到映射配置中,或者其它情況,在 AutoMapper 中,我們可以使用 <code>configuration.AssertConfigurationIsValid();</code> 來檢查映射;在 ABP 中則可使用 <code>validate: true</code> 參數來開啟檢查。

在 <code>AbpBase.Application</code> 項目中,添加 Nuget 包,搜尋 <code>Volo.Abp.ObjectMapping</code> 并下載下傳相應的穩定版本。

IObjectMapper 有兩個,一個是 AutoMapper 的接口,一個是  <code>Volo.Abp.ObjectMapping</code>  的 泛型接口。

AutoMapper  的 IObjectMapper  不好用,是以别用;用  <code>Volo.Abp.ObjectMapping</code>  的 <code>IObjectMapper</code>。

ObjectMapper 是 AutoMapper 中的,我們可以直接在控制器等位置,使用 <code>ObjectMapper</code> 注入,然後通過 ObjectMapper 執行個體映射對象。

ObjectMapper 隻有 <code>.Map()</code> 這個方法用得順手。

也可以通過依賴注入使用 <code>IObjectMapper</code> 接口。

但是因為 ObjectMapper 是泛型類,每種類型的 DTO 都要注入一次的話,會很麻煩,是以這種方案也可以抛棄。

而 泛型的 <code>IObjectMapper</code> 是一個抽象,我們使用  <code>IObjectMapper</code> 做依賴注入的話,後續如果替換為别的對象映射架構,則不需要修改原有代碼即可完成替代。而且  <code>IObjectMapper</code>  比較舒服。

使用示例:

ABP架構提供了 實體擴充系統 允許你 添加額外屬性 到已存在的對象 無需修改相關類。這句話是抄 ABP 官方文檔的。

要支援對象拓展映射,則需要開啟配置:

時間有限,筆者這裡隻把官方文檔的内容講清楚,讀者看完後,需要繼續查閱官方文檔,完整了解對象拓展。

ObjectExtensionManager 是一個拓展對象映射類,可以顯式為類拓展一些額外的屬性,這個類型在 <code>Volo.Abp.ObjectMapping</code> 中定義。

ObjectExtensionManager  是一個類型,但是我們不能直接 new 它,或者使用依賴注入,隻能通過 <code>ObjectExtensionManager.Instance</code> 這個屬性擷取新的類型。我們無需關心它是用了啥設計模式,還是因為緩存之類的原因這樣設計。

ObjectExtensionManager  有兩種屬性,其說明如下:

<code>AddOrUpdate</code> :是定義對象額外屬性或更新對象額外屬性的主要方法;

<code>AddOrUpdateProperty</code>:快捷地定義單個拓展屬性的方法;

<code>AddOrUpdateProperty</code> 用于定義單個屬性,<code>AddOrUpdate</code> 是一個容器,可以包含多個 <code>AddOrUpdateProperty</code>。

<code>AddOrUpdateProperty</code> 示例代碼如下:

<code>AddOrUpdate</code>  的示例代碼如下:

當然,我們還可以同時為多個類型同時定義一個額外的屬性:

如果需要定義多個屬性,則可以使用 <code>AddOrUpdate</code>:

另外它還可以設定預設值、增加驗證規則等,這些筆者就不再贅述,讀者感興趣可以點選連結進入官方文檔檢視。