Configuring the AutoMapper mapping rule "turn"

Source: Internet
Author: User



Configuring AutoMapper Mapping Rules

AutoMapper is based on conventions, so before the utility map, we need to configure the mapping rules first.

public class source{Public    int somevalue {get; set;}    public string Anothervalue {get; set;}} public class destination{Public    int somevalue {get; set;}}

In the above code, we have defined two classes, and we need to map the object of the source class to the object of the destination class. To complete this operation, we need to configure the AutoMapper as follows:

Mapper.createmap<source, destination> ();

To test:

SOURCE src = new Source () {somevalue = 1, Anothervalue = "2"};D estination dest = mapper.map<destination> (src); obje Ctdumper.write (dest);

We can see the property values of the Dest object in the console:

This allows us to complete a simple automapper mapping.

Usage of profile

Profile provides a named mapping class, and all subclasses that inherit from the profile class are a collection of mappings.

Let's take a look at the usage of the profile, which still uses the source class and the destination class in this example.

public class sourceprofile:profile{    protected override void Configure ()    {        Createmap<source, Destination> ();    }}

We can then rewrite the Configure method in profile to complete the configuration of the mapping rule. Initialize the mapper rule from profile:

Mapper.initialize (x = x.addprofile<sourceprofile> ());

In a profile, we can accomplish the conventions of multiple, more complex rules:

public class destination2{Public    int somevalue {get; set;}    public string AnotherValue2 {get; set;}} public class sourceprofile:profile{    protected override void Configure ()    {        //source->destination        Createmap<source, destination> ();        Source->destination2        Createmap<source, destination2> (). Formember (d = d.anothervalue2, opt = =        {            opt. Mapfrom (s = = S.anothervalue);}        );}    }

AutoMapper Best Practices

This section will discuss the question of where AutoMapper's rules are written.

In the last paragraph, we already know how to use AutoMapper for simple object mapping, but in actual projects we have many classes to map (from entity to DTO, or from entity to ViewModel, etc.). How to organize so many maps will become a problem.

First we need to define a Configuration.cs class that provides a portal to the AutoMapper rule configuration, which provides only a static method that is called when the program is first run to complete the configuration.

When there are multiple profiles, we can add this:

public class configuration{public    static void Configure ()    {        mapper.initialize (cfg =        {            cfg). Addprofile<profiles.sourceprofile> ();            Cfg. Addprofile<profiles.orderprofile> ();            Cfg. Addprofile<profiles.calendareventprofile> ();}        );}    }

You only need to call the Configure method when the program is running.

With these implementations in view, we can then add the AutoMapper folder to the project, with the following folder structure:

The configuration is our statically configured entry class; The Profiles folder is the folder for all of our profile classes. In the case of MVC, we need to call it in global:

AutoMapper.Configuration.Configure ();
Flattened mapping (Flattening)

By default, our source class and the destination class are mapped based on the property name. In addition, the default mapping rules have the following two cases, which we call flattened mapping, that is, when the source class does not contain attributes in the destination class, AutoMapper will split the attributes in the destination class, or match the "Get" The beginning of the method, for example:

Order class:

public class order{public    customer customer {get; set;}    Public decimal gettotal ()    {        return 100M;    }}

The Order class contains a customer object and a Gettotal method, in order to facilitate the demonstration, I directly return the Gettotal method to 100;

The customer class is defined as follows:

public class customer{Public    string Name {get; set;}}

The Orderdto class is defined as follows:

public class orderdto{Public    string CustomerName {get; set;}    public string Total {get; set;}}

When we are mapping, we do not need a special configuration to complete the mapping from order to orderdto.

public class orderprofile:profile{    protected override void Configure ()    {        Createmap<entity.order, Dto.orderdto> ();    }}

Test code:

Entity.customer Customer = new Entity.customer () {Name = "Tom"}; Entity.order Order = new Entity.order () {customer = customer};D to. Orderdto orderdto = mapper.map<dto.orderdto> (order); Objectdumper.write (order, 2); Objectdumper.write (OrderDto );

Test results:

Specify mapping fields (Projection)

In a real business environment, the fields of our source class and the destination class cannot match one to the other, and at this point we need to specify their actual mapping relationships, for example:

public class calendarevent{Public    DateTime Date {get; set;}    public string Title {get; set;}} public class calendareventform{Public    DateTime eventdate {get; set;}    public int Eventhour {get; set;}    public int Eventminute {get; set;}    public string DisplayTitle {get; set;}}

In these two classes, the Calendarevent date will be split into Calendareventform date, time, and three fields, and the title will correspond to the DisplayTitle field, then the corresponding profile is defined as follows:

public class calendareventprofile:profile{    protected override void Configure ()    {        createmap< Entity.calendarevent, entity.calendareventform> ()            . Formember (dest = dest. Eventdate, opt = opt. Mapfrom (src = src. date.date))            . Formember (dest = dest. Eventhour, opt = opt. Mapfrom (src = src. Date.hour))            . Formember (dest = dest. Eventminute, opt = opt. Mapfrom (src = src. Date.minute))            . Formember (dest = dest. DisplayTitle, opt = opt. Mapfrom (src = src. (Title));}    }

Test code:

Entity.calendarevent calendarevent = new Entity.calendarevent () {    Date = DateTime.Now,    Title = "Demo Event"}; Entity.calendareventform calendareventform = mapper.map<entity.calendareventform> (calendarEvent); O Bjectdumper.write (Calendareventform);

Test results:

Verifying configuration items (config Validation)

AutoMapper provides a validation mechanism to determine if all the properties in the destination class are mapped and throws an exception if there are properties that are not mapped.

Use of validation:

Mapper.assertconfigurationisvalid ();

For example:

public class source{Public    int somevalue {get; set;}    public string Anothervalue {get; set;}}

Destination code:

public class destination{Public    int SOMEVALUEFFF {get; set;}}

Test:

Mapper.createmap<entity.source, entity.destination> (); Mapper.assertconfigurationisvalid ();

The automapperconfigurationexception exception will appear when you run the program:

This is because SOMEVALUEFFF does not cause a corresponding field in the source class.

The methods to resolve this exception are:

Specify the mapping fields, for example:

Mapper.createmap<entity.source, entity.destination> ()    . Formember (dest = dest. SOMEVALUEFFF, opt =    {        opt. Mapfrom (src = src. somevalue);    });

Or use the Ignore method:

Mapper.createmap<entity.source, entity.destination> ()    . Formember (dest = dest. SOMEVALUEFFF, opt =    {        opt. Ignore ();    });

Or using a custom parser, the custom parser is described below.

Customized parser (custom value resolvers)

AutoMapper allows us to customize the parser to complete the conversion of the value from source to destination. For example:

public class source{Public    int Value1 {get; set;}    public int Value2 {get; set;}} public class destination{Public    int total {get; set;}}

The total property does not exist in source, and if you create a mapping rule now, you will inevitably throw an exception when mapping. At this point we need to use a custom parser to complete the mapping.

The custom parser needs to implement the Ivalueresolver interface, the interface is defined as follows:

public interface ivalueresolver{    resolutionresult Resolve (Resolutionresult source);}

We come from defining a resolver:

public class Customresolver:valueresolver<source, int>{    protected override int Resolvecore (source source) c2/>{        return source. Value1 + source. Value2;}    }

Then use this parser in the mapping rule:

public class sourceprofile:profile{    protected override void Configure ()    {        //source->destination        Createmap<source, destination> ()            . Formember (dest = dest. Total, opt + =            {                opt. Resolveusing<customresolver> ();}            );}    }

Test code:

SOURCE src = new Source () {    Value1 = 1,    Value2 = 2};D estination dest = mapper.map<destination> (src); Object Dumper.write (dest);

Test results:

In the use of custom resolver, we can also specify resolver constructors, for example:

Source->destinationcreatemap<source, destination> ()    . Formember (dest = dest. Total, opt + =    {        opt. Resolveusing<customresolver> ()            

New Customresolver

());    });
Custom type converter (custom types converters)

AutoMapper uses a custom type converter through convertusing. There are three ways to use convertusing:

void Convertusing (Func<tsource, tdestination> mappingfunction); void Convertusing (Itypeconverter<tsource, tdestination> converter); void convertusing<ttypeconverter> () where ttypeconverter:itypeconverter< TSource, tdestination>;

When we have the following source class and destination class:

public class source{Public    string Value1 {get; set;}} public class destination{Public    int Value1 {get; set;}}

We can use the following configuration:

public class sourceprofile:profile{    protected override void Configure ()    {        //string->int        Createmap<string, int> ()            . Convertusing (Convert.ToInt32);        Source->destination        Createmap<source, destination> ();    }}

In the above configuration, we first created a type conversion from string to int, which uses the system's own Convert.ToInt32 conversion method.

In addition to this method, we can also customize the type converter:

public class Customconverter:itypeconverter<source, destination>{public    Destination Convert ( Resolutioncontext context)    {        Source src = context. Sourcevalue as Source;        Destination dest = new Destination ();        Dest. Value1 = System.Convert.ToInt32 (src. VALUE1);        return dest;}    }

With this converter, we can bypass the conversion of string to int and directly convert the object of the source class to the object of the destination class.

The corresponding configuration is as follows:

public class sourceprofile:profile{    protected override void Configure ()    {        //source->destination        Createmap<source, destination> ()            . Convertusing<customconverter> ();    }}

Alternatively, we can use the following configuration:

public class sourceprofile:profile{    protected override void Configure ()    {        //source->destination        Customconverter converter = new Customconverter ();        Createmap<source, destination> ()            . Convertusing (Converter);    }}
Null value substitution (null substitution)

Null substitution allows us to use the specified value to replace null values when the null value in the source object is converted to a value of destination.

public class source{Public    string Value {get; set;}} public class destination{Public    string Value {get; set;}}

Configuration code:

public class sourceprofile:profile{    protected override void Configure ()    {        //source->destination        Createmap<source, destination> ()            . Formember (dest = dest. Value, opt + =            {                opt. Nullsubstitute ("Original value is null");}            );}    }

Test code:

SOURCE src = new source ();D estination dest = mapper.map<destination> (src); Objectdumper.write (dest);

Test results:

Conditional mapping (Conditional mapping)

A conditional mapping is mapped only when the value of the attribute in the source class satisfies a certain condition. For example:

public class foo{public    int Baz;} public class bar{public    uint Baz;}

The corresponding configuration code is as follows:

Mapper.createmap<foo, bar> ()    . Formember (dest = dest.baz, opt = =    {        opt. Condition (src = (src.baz >= 0);    });


Transferred from: http://www.cnblogs.com/youring2/p/automapper.html

Configuring the AutoMapper mapping rule "turn"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.