【C#】AutoMapper 使用手冊

来源:https://www.cnblogs.com/gl1573/archive/2020/06/12/13098031.html
-Advertisement-
Play Games

本文基於 AutoMapper 9.0.0 AutoMapper 是一個對象-對象映射器,可以將一個對象映射到另一個對象。 官網地址:http://automapper.org/ 官方文檔:https://docs.automapper.org/en/latest/ 1 入門例子 public cl ...


目錄

本文基於 AutoMapper 9.0.0

AutoMapper 是一個對象-對象映射器,可以將一個對象映射到另一個對象。

官網地址:http://automapper.org/

官方文檔:https://docs.automapper.org/en/latest/

1 入門例子

public class Foo
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class FooDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public void Map()
{
    var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());

    var mapper = config.CreateMapper();

    Foo foo = new Foo { ID = 1, Name = "Tom" };

    FooDto dto = mapper.Map<FooDto>(foo);
}

2 註冊

在使用 Map 方法之前,首先要告訴 AutoMapper 什麼類可以映射到什麼類。

var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());

每個 AppDomain 只能進行一次配置。這意味著放置配置代碼的最佳位置是在應用程式啟動中,例如 ASP.NET 應用程式的 Global.asax 文件。

從 9.0 開始 Mapper.Initialize 方法就不可用了。

2.1 Profile

Profile 是組織映射的另一種方式。新建一個類,繼承 Profile,併在構造函數中配置映射。

public class EmployeeProfile : Profile
{
    public EmployeeProfile()
    {
        CreateMap<Employee, EmployeeDto>();
    }
}

var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile<EmployeeProfile>();
});

Profile 內部的配置僅適用於 Profile 內部的映射。應用於根配置的配置適用於所有創建的映射。

AutoMapper 也可以在指定的程式集中掃描從 Profile 繼承的類,並將其添加到配置中。

var config = new MapperConfiguration(cfg =>
{
    // 掃描當前程式集
    cfg.AddMaps(System.AppDomain.CurrentDomain.GetAssemblies());
    
    // 也可以傳程式集名稱(dll 名稱)
    cfg.AddMaps("LibCoreTest");
});

3 配置

3.1 命名約定

預設情況下,AutoMapper 基於相同的欄位名映射,並且是 不區分大小寫 的。

但有時,我們需要處理一些特殊的情況。

  • SourceMemberNamingConvention 表示源類型命名規則
  • DestinationMemberNamingConvention 表示目標類型命名規則

LowerUnderscoreNamingConventionPascalCaseNamingConvention 是 AutoMapper 提供的兩個命名規則。前者命名是小寫並包含下劃線,後者就是帕斯卡命名規則(每個單詞的首字母大寫)。

我的理解,如果源類型和目標類型分別採用了 蛇形命名法駝峰命名法,那麼就需要指定命名規則,使其能正確映射。

public class Foo
{
    public int Id { get; set; }

    public string MyName { get; set; }
}

public class FooDto
{
    public int ID { get; set; }

    public string My_Name { get; set; }
}

public void Map()
{
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Foo, FooDto>();

        cfg.SourceMemberNamingConvention = new PascalCaseNamingConvention();
        cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();
    });

    var mapper = config.CreateMapper();

    Foo foo = new Foo { Id = 2, MyName = "Tom" };

    FooDto dto = mapper.Map<FooDto>(foo);
}

3.2 配置可見性

預設情況下,AutoMapper 僅映射 public 成員,但其實它是可以映射到 private 屬性的。

var config = new MapperConfiguration(cfg =>
{
    cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.SetMethod.IsPrivate;
    cfg.CreateMap<Source, Destination>();
});

需要註意的是,這裡屬性必須添加 private set,省略 set 是不行的。

3.3 全局屬性/欄位過濾

預設情況下,AutoMapper 嘗試映射每個公共屬性/欄位。以下配置將忽略欄位映射。

var config = new MapperConfiguration(cfg =>
{
	cfg.ShouldMapField = fi => false;
});

3.4 識別首碼和尾碼

var config = new MapperConfiguration(cfg =>
{
    cfg.RecognizePrefixes("My");
    cfg.RecognizePostfixes("My");
}

3.5 替換字元

var config = new MapperConfiguration(cfg =>
{
    cfg.ReplaceMemberName("Ä", "A");
});

這功能我們基本上用不上。

4 調用構造函數

有些類,屬性的 set 方法是私有的。

public class Commodity
{
    public string Name { get; set; }

    public int Price { get; set; }
}

public class CommodityDto
{
    public string Name { get; }

    public int Price { get; }

    public CommodityDto(string name, int price)
    {
        Name = name;
        Price = price * 2;
    }
}

AutoMapper 會自動找到相應的構造函數調用。如果在構造函數中對參數做一些改變的話,其改變會反應在映射結果中。如上例,映射後 Price 會乘 2。

禁用構造函數映射:

var config = new MapperConfiguration(cfg => cfg.DisableConstructorMapping());

禁用構造函數映射的話,目標類要有一個無參構造函數。

5 數組和列表映射

數組和列表的映射比較簡單,僅需配置元素類型,定義簡單類型如下:

public class Source
{
    public int Value { get; set; }
}

public class Destination
{
    public int Value { get; set; }
}

映射:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Source, Destination>();
});
IMapper mapper = config.CreateMapper();

var sources = new[]
{
    new Source { Value = 5 },
    new Source { Value = 6 },
    new Source { Value = 7 }
};

IEnumerable<Destination> ienumerableDest = mapper.Map<Source[], IEnumerable<Destination>>(sources);
ICollection<Destination> icollectionDest = mapper.Map<Source[], ICollection<Destination>>(sources);
IList<Destination> ilistDest = mapper.Map<Source[], IList<Destination>>(sources);
List<Destination> listDest = mapper.Map<Source[], List<Destination>>(sources);
Destination[] arrayDest = mapper.Map<Source[], Destination[]>(sources);

具體來說,支持的源集合類型包括:

  • IEnumerable
  • IEnumerable
  • ICollection
  • ICollection
  • IList
  • IList
  • List
  • Arrays

映射到現有集合時,將首先清除目標集合。如果這不是你想要的,請查看AutoMapper.Collection。

5.1 處理空集合

映射集合屬性時,如果源值為 null,則 AutoMapper 會將目標欄位映射為空集合,而不是 null。這與 Entity Framework 和 Framework Design Guidelines 的行為一致,認為 C# 引用,數組,List,Collection,Dictionary 和 IEnumerables 永遠不應該為 null

5.2 集合中的多態

這個官方的文檔不是很好理解。我重新舉個例子。實體類如下:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class Employee2 : Employee
{
    public string DeptName { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class EmployeeDto2 : EmployeeDto
{
    public string DeptName { get; set; }
}

數組映射代碼如下:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>().Include<Employee2, EmployeeDto2>();
    cfg.CreateMap<Employee2, EmployeeDto2>();
});
IMapper mapper = config.CreateMapper();

var employees = new[]
{
    new Employee { ID = 1, Name = "Tom" },
    new Employee2 { ID = 2, Name = "Jerry", DeptName = "R & D" }
};

var dto = mapper.Map<Employee[], EmployeeDto[]>(employees);

可以看到,映射後,dto 中兩個元素的類型,一個是 EmployeeDto,一個是 EmployeeDto2,即實現了父類映射到父類,子類映射到子類。

如果去掉 Include 方法,則映射後 dto 中兩個元素的類型均為 EmployeeDto

6 方法到屬性映射

AutoMapper 不僅能實現屬性到屬性映射,還可以實現方法到屬性的映射,並且不需要任何配置,方法名可以和屬性名一致,也可以帶有 Get 首碼。

例如下例的 Employee.GetFullName() 方法,可以映射到 EmployeeDto.FullName 屬性。

public class Employee
{
    public int ID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string GetFullName()
    {
        return $"{FirstName} {LastName}";
    }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string FullName { get; set; }
}

7 自定義映射

當源類型與目標類型名稱不一致時,或者需要對源數據做一些轉換時,可以用自定義映射。

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public DateTime JoinTime { get; set; }
}

public class EmployeeDto
{
    public int EmployeeID { get; set; }

    public string EmployeeName { get; set; }

    public int JoinYear { get; set; }
}

如上例,IDEmployeeID 屬性名不同,JoinTimeJoinYear 不僅屬性名不同,屬性類型也不同。

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>()
        .ForMember("EmployeeID", opt => opt.MapFrom(src => src.ID))
        .ForMember(dest => dest.EmployeeName, opt => opt.MapFrom(src => src.Name))
        .ForMember(dest => dest.JoinYear, opt => opt.MapFrom(src => src.JoinTime.Year));
});

8 扁平化映射

對象-對象映射的常見用法之一是將複雜的對象模型並將其展平為更簡單的模型。

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

如果目標類型上的屬性,與源類型的屬性、方法都對應不上,則 AutoMapper 會將目標成員名按駝峰法拆解成單個單詞,再進行匹配。例如上例中,EmployeeDto.DepartmentID 就對應到了 Employee.Department.ID

8.1 IncludeMembers

如果屬性命名不符合上述的規則,而是像下麵這樣:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int DepartmentID { get; set; }

    public string DepartmentName { get; set; }
}

Department 類中的屬性名,直接跟 EmployeeDto 類中的屬性名一致,則可以使用 IncludeMembers 方法指定。

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>().IncludeMembers(e => e.Department);
    cfg.CreateMap<Department, EmployeeDto>();
});

9 嵌套映射

有時,我們可能不需要展平。看如下例子:

public class Employee
{
    public int ID { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public Department Department { get; set; }
}

public class Department
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Heads { get; set; }
}

public class EmployeeDto
{
    public int ID { get; set; }

    public string Name { get; set; }

    public DepartmentDto Department { get; set; }
}

public class DepartmentDto
{
    public int ID { get; set; }

    public string Name { get; set; }
}

我們要將 Employee 映射到 EmployeeDto,並且將 Department 映射到 DepartmentDto

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Employee, EmployeeDto>();
    cfg.CreateMap<Department, DepartmentDto>();
});

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • c#去掉小數點後的無效0 ,保留指定位數的小數,比如10.0顯示成10,小數部分會四捨五入 float value = 0.0500f; value.ToString("0.##");//保留兩位小數輸出0.05 var percent = ((float) 100/(float)100).ToSt ...
  • 三位一逗:使用“N”(使用n也可以,不區分大小寫),“N”後面的數字是小數位數 //三位一逗,保留5位小數 Console.WriteLine($"{9999.12345.ToString("N5")}"); //三位一逗,四捨五入,保留2位小數 Console.WriteLine($"{9999. ...
  • 常見的IIS部署WebService,或者開發時,調試WebService的問題 1、想通過瀏覽器進行調用測試,比較快速方便 VS直接運行,還可以選用自己喜歡的瀏覽器進行調試,前提需要在 Web.Config配置文件中,增加配置信息 system.web節點下增加如下: <webServices> ...
  • CheckBox 選中預設的樣式是一個勾,如圖所示: 那麼我們怎麼樣才能修改這個 "勾" 呢? 我們只需要改變它的模板樣式即可,如下所示: 我們只需要在 Blend中 畫一個圖形,然後將數據替換掉 Data中的數據即可,如下所示,我畫的是一個愛心: 運行效果如下: ...
  • Asp.Net WebApi 上傳文件方法 實現功能: 1.原生js調用api上傳 2.jq ajax調用api上傳 後端 Model /// <summary> /// 上傳文件(如果遇到不明白的或者發現BUG請加入QQ群:Java .Net Go PHP UI群:574879752 直接@群主) ...
  • @ 簡介 什麼是Dikeko.ORM? Dikeko.ORM是一個簡單的.NET輕量級的ORM,目前僅支持SqlServer資料庫。 安裝 .NET版:https://www.nuget.org/packages/Dikeko.ORM PM>Install-Package Dikeko.ORM .N ...
  • Blazor WebAssembly可以在瀏覽器上跑C#代碼,但是很多時候顯然還是需要跟JavaScript打交道。比如操作dom,當然跟angular、vue一樣不提倡直接操作dom;比如瀏覽器的後退導航。反之JavaScript也有可能需要調用C#代碼來實現一些功能,畢竟客戶的需求是千變萬化的, ...
  • ps:本文需要先把abp的源碼下載一份來下,跟著一起找實現,更容易懂 在abp中,對於許可權和菜單使用靜態來管理,菜單的載入是在登陸頁面的地方(具體是怎麼知道的,瀏覽器按F12,然後去sources中去找) 這個/AbpScripts/GetScripts是獲取需要初始化的script,源自AbpSc ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...