jubi
jubi

Reputation: 625

how to map using Automapper

I have requirement to map two objects. The requirement is train reservation details which will have towardsjourney and return journey details.

public class ReservationSource
{
    public string ReservationNumber{get;set;} 
    public TravelS towardsTravelS{get;set;}
    public TravelS returnTravelS{get;set;}
}

This is the class which is in the ReservationSource class which is to capture towards and return journey details.

public class TravelS
{
   public string travelId{get;set;}
   public ICollection<JourneyS> Journeys{get;set;}
}

Above is the reservation source object. This source needs a mapping to the destination object. Destination object is given below.

public class ReservationDestination
{
    public string ReservationNumber{get;set;}
    public TravelD towardsTravelD{get;set;}
    public TravelD returnTravelD{get;set;}

}

public class TravelD
{
    public string travelId{get;set;}
    public ICollection<JourneyD> Journeys{get;set;}
}
public class JourneyD
{
    public string JourneyId{get;set;}
}
public class JourneyS
{
    public string JourneyId{get;set;}
}

This is my destination object . Here i want to map my source to destination. How do i define mapping config and map .

var config = new mappingConfiguration(cfg=>
{
cfg.CreateMap<ReservationSource,ReservationDestination>()
});

Imapper map = config.CreateMapper();

This part of code maps only the reservationNumber to the destination object. Can someone help me to map all objects. That is towardsTravelS to towardsTravelD and returnTravelS to returnTravelD.

.net core version : 3.1

Upvotes: 2

Views: 3070

Answers (2)

mohammadmahdi Talachi
mohammadmahdi Talachi

Reputation: 601

Add this in your services in startup :

it's reusable and cleaner

 public void ConfigureServices(IServiceCollection services)
{
            services.AddAutoMapper(Assembly.GetExecutingAssembly());
}

add these interface and class in your project

public interface IMapFrom<T>
{
        void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
using AutoMapper;
using System;
using System.Linq;
using System.Reflection;

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());
        }

        private void ApplyMappingsFromAssembly(Assembly assembly)
        {
                var types = assembly.GetExportedTypes()
                .Where(t => t.GetInterfaces()
                .Any(i =>i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
                .ToList();

            foreach (var type in types)
            {
                var instance = Activator.CreateInstance(type);

                var methodInfo = type.GetMethod("Mapping")
                    ?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");

                methodInfo?.Invoke(instance, new object[] { this });

            }
        }
    }

and your source model be like this (map ReservationSource to ReservationSource):

 public class ReservationSource : IMapFrom<ReservationSource>
    {

        public string Name { get; set; }

        public string City { get; set; }

        public void Mapping(Profile profile)
        {
            profile.CreateMap<ReservationSource,ReservationDestination>()
                       .ForMember(dest => dest.ReturnTravelD, opt => opt.MapFrom(src => src.ReturnTravelS))
                       .ForMember(dest => dest.TowardsTravelD, opt => opt.MapFrom(src => src.TowardsTravelS));
        }
    }

Upvotes: 4

user10608418
user10608418

Reputation:

First of all you forgot to mention this but I assume there also is a class TravelS that looks like this:

public class TravelS
{
    public string TravelId { get; set; }
}

There are a few things missing in your configuration. At the moment AutoMapper doesn't know it has to map properties with different names (TowardsTravelS => TowardsTravelD etc) so we have to define those aswell:

cfg.CreateMap<ReservationSource, ReservationDestination>()
    .ForMember(dest => dest.ReturnTravelD, opt => opt.MapFrom(src => src.ReturnTravelS))
    .ForMember(dest => dest.TowardsTravelD, opt => opt.MapFrom(src => src.TowardsTravelS));

Here we tell AutoMapper that these properties that have different names need to be mapped.

Secondly TravelS and TravelD are different classes so we need to configure them for mapping as well:

cfg.CreateMap<TravelS, TravelD>();

So we now have something like this:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<ReservationSource, ReservationDestination>()
      .ForMember(dest => dest.ReturnTravelD, opt => opt.MapFrom(src => src.ReturnTravelS))
      .ForMember(dest => dest.TowardsTravelD, opt => opt.MapFrom(src => src.TowardsTravelS));
    cfg.CreateMap<TravelS, TravelD>();
});

var mapper = config.CreateMapper();

var source = new ReservationSource
{
    ReservationNumber = "9821",
    ReturnTravelS = new TravelS
    {
      TravelId = "1"
    },
    TowardsTravelS = new TravelS
    {
      TravelId = "2"
    }
};

var destination = mapper.Map<ReservationDestination>(source);

Console.WriteLine(JsonSerializer.Serialize(destination));

Output:

{"ReservationNumber":"9821","TowardsTravelD":{"TravelId":"2"},"ReturnTravelD":{"TravelId":"1"}}

Try it for yourself here: https://dotnetfiddle.net/FfccVR

Upvotes: 3

Related Questions