This article is based on AutoMapper 9.0.0
AutoMapper is an object-object mapper that maps one object to another.
Official website address:/
Official Documentation:/en/latest/
1 Introduction Example
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 => <Foo, FooDto>()); var mapper = (); Foo foo = new Foo { ID = 1, Name = "Tom" }; FooDto dto = <FooDto>(foo); }
2 Register
In use Map
Before the method, you must first tell AutoMapper what class can be mapped to which class.
var config = new MapperConfiguration(cfg => <Foo, FooDto>());
Each AppDomain can only be configured once. This means that the best place to place configuration code is in application startup, such as the application's file.
Starting from 9.0
The method is not available.
2.1 Profile
Profile
is another way to organize mapping. Create a new class, inherit Profile
, and configure the mapping in the constructor.
public class EmployeeProfile : Profile { public EmployeeProfile() { CreateMap<Employee, EmployeeDto>(); } } var config = new MapperConfiguration(cfg => { <EmployeeProfile>(); });
Profile
Internal configuration only applies toProfile
Internal mapping. The configuration applied to the root configuration applies to all created maps.
AutoMapper can also scan from the specified assembly Profile
Inherited class and add it to the configuration.
var config = new MapperConfiguration(cfg => { // Scan the current assembly (()); // You can also pass the assembly name (dll name) ("LibCoreTest"); });
3 Configuration
3.1 Naming Convention
By default, AutoMapper is based on the same field name map and is case-insensitive.
But sometimes, we need to deal with some special situations.
-
SourceMemberNamingConvention
Represents source type naming rules -
DestinationMemberNamingConvention
Represents the target type naming rules
LowerUnderscoreNamingConvention
andPascalCaseNamingConvention
are two naming rules provided by AutoMapper. The former is named in lowercase and contains underscores, while the latter is the Pascal naming rules (the initial letter of each word is capitalized).
My understanding is that if the source type and target type use serpentine nomenclature and camel nomenclature respectively, then you need to specify naming rules so that they can map correctly.
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 => { <Foo, FooDto>(); = new PascalCaseNamingConvention(); = new LowerUnderscoreNamingConvention(); }); var mapper = (); Foo foo = new Foo { Id = 2, MyName = "Tom" }; FooDto dto = <FooDto>(foo); }
3.2 Configuring Visibility
By default, AutoMapper only maps public
Member, but it can actually be mapped to private
attributes.
var config = new MapperConfiguration(cfg => { = p => || ; <Source, Destination>(); });
It should be noted that the attribute must be added hereprivate set
, omitted set
That's not possible.
3.3 Global attribute/field filtering
By default, AutoMapper tries to map each public property/field. The following configuration ignores field mapping.
var config = new MapperConfiguration(cfg => { = fi => false; });
3.4 Identify prefixes and suffixes
var config = new MapperConfiguration(cfg => { ("My"); ("My"); }
3.5 Replace characters
var config = new MapperConfiguration(cfg => { ("Ä", "A"); });
We basically don't use this function.
4 Call the constructor
Some classes, attributesset
The method is private.
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 will automatically find the corresponding constructor call. If some changes are made to the parameters in the constructor, the changes will be reflected in the mapping result. As shown in the above example, after mapping Price
Will multiply 2.
Disable constructor mapping:
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 will automatically find the corresponding constructor call. If some changes are made to the parameters in the constructor, the changes will be reflected in the mapping result. As in the above example, Price will be multiplied by 2 after mapping.
Disable constructor mapping:
var config = new MapperConfiguration(cfg => ());
If constructor mapping is disabled, the target class must have a parameterless constructor.
5 Array and List Mapping
The mapping of arrays and lists is relatively simple. You only need to configure the element type and define the simple type as follows:
public class Source { public int Value { get; set; } } public class Destination { public int Value { get; set; } }
Mapping:
var config = new MapperConfiguration(cfg => { <Source, Destination>(); }); IMapper mapper = (); var sources = new[] { new Source { Value = 5 }, new Source { Value = 6 }, new Source { Value = 7 } }; IEnumerable<Destination> ienumerableDest = <Source[], IEnumerable<Destination>>(sources); ICollection<Destination> icollectionDest = <Source[], ICollection<Destination>>(sources); IList<Destination> ilistDest = <Source[], IList<Destination>>(sources); List<Destination> listDest = <Source[], List<Destination>>(sources); Destination[] arrayDest = <Source[], Destination[]>(sources);
Specifically, supported source collection types include:
- IEnumerable
- IEnumerable
- ICollection
- ICollection
- IList
- IList
- List
- Arrays
When mapped to an existing collection, the target collection is first cleared. If this is not what you want, check it out.
5.1 Processing empty collections
When mapping collection attributes, if the source value isnull
, then AutoMapper maps the target field to an empty collection, instead ofnull
. This is consistent with the behavior of Entity Framework and Framework Design Guidelines, which argues that C# references, arrays, List, Collection, Dictionary, and IEnumerables should never be null
。
5.2 Polymorphism in a collection
This official documentation is not easy to understand. Let me give you another example. The entity class is as follows:
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; } }
The array mapping code is as follows:
var config = new MapperConfiguration(cfg => { <Employee, EmployeeDto>().Include<Employee2, EmployeeDto2>(); <Employee2, EmployeeDto2>(); }); IMapper mapper = (); var employees = new[] { new Employee { ID = 1, Name = "Tom" }, new Employee2 { ID = 2, Name = "Jerry", DeptName = "R & D" } }; var dto = <Employee[], EmployeeDto[]>(employees);
It can be seen that after mapping, the types of two elements in dto are EmployeeDto and EmployeeDto2, which implements the mapping of the parent class to the parent class and the mapping of the child class to the child class.
If the Include method is removed, the types of both elements in the mapped dto are EmployeeDto.
6 Method to attribute mapping
AutoMapper can not only implement attribute-to-property mapping, but also implement method-to-property mapping, and does not require any configuration. The method name can be the same as the attribute name, or it can also be accompanied byGet
Prefix.
For example, the following example()
Methods that can be mapped to
property.
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 Custom Mapping
Custom mapping can be used when the source type does not match the target type name, or when some conversions are required to make the source data.
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; } }
As in the above example,ID
andEmployeeID
Different attribute names,JoinTime
and JoinYear
Not only are the attribute names different, but the attribute types are also different.
var config = new MapperConfiguration(cfg => { <Employee, EmployeeDto>() .ForMember("EmployeeID", opt => (src => )) .ForMember(dest => , opt => (src => )) .ForMember(dest => , opt => (src => )); });
8 Flat Mapping
One of the common uses of object-object mapping is to flatten complex object models into simpler models.
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; } }
If the attributes on the target type do not correspond to the attributes and methods of the source type, AutoMapper will disassemble the target member name into a single word according to the camel method and then match it. For example, in the above example, it corresponds to .
8.1 IncludeMembers
If the attribute naming does not comply with the above rules, it is like this:
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
The attribute name in the class is directly followed by EmployeeDto
If the attribute names in the class are the same, you can use it IncludeMembers
Method Specifies.
9 Nested Mapping
Sometimes, we may not need to flatten. See the following example:
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; } }
We want toEmployee
Map to EmployeeDto
, and will Department
Map to DepartmentDto
。
var config = new MapperConfiguration(cfg => { <Employee, EmployeeDto>(); <Department, DepartmentDto>(); });
The above is the detailed content of the usage method of C# AutoMapper. For more information on the usage of C# AutoMapper, please pay attention to my other related articles!