2

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

2 Answers 2

4

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));
        }
    }
Sign up to request clarification or add additional context in comments.

1 Comment

This doesn't work when use conditionally like .ForMember(d => d.ReturnTravelD, opt => opt.MapFrom(s => s.ReturnTravelS != null ? s.ReturnTravelS.Where(p => p.CompletedOn.HasValue ) : null));
3

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

2 Comments

Thanks it worked. If i want to update few info like realtime information of the train (actual arraival/departure) ( imagine i get this from a different source), can i update the data which we have mapped through automapper. Say i have a collection/List of Travel and i need few info in travel class from a different api and after mapping all the other fields i want to update few property. Note: The collection/List is in the innerclass
Well you'll have to find the right object to update yourself. But you can map to existing objects (there is a Map<TSource, TDestination>(TSource source, TDestination) overload). This means you can chain maps from multiple source objects (or update a destination object at a later point). Just make sure that every type you use as source needs to have a configured mapping to the destination type. Good luck with the project!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.