Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper issue when mapping back to DTO from ViewModel

Im having a problem in mapping back to DTO.

DTO :

public class ServiceEntity : BaseChild
{
    public int Id { get; set; }
}

public class BaseChild
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Salary { get; set; }
    public string BkName { get; set; }
    public int BkPrice { get; set; }
    public string BkDescription { get; set; }
}

ViewModel :

public class BusinessEntity 
{
    public ChildBussiness Details { get; set; }
}

public class ChildBussiness
{
    public string NameFirst { get; set; }
    public string LastName { get; set; }
    public Books BookDetails { get; set; }
    public string Salary { get; set; }
}

public class Books
{
    public string BookName { get; set; }
    public int BookPrice { get; set; }
    public string BookDescription { get; set; }
}

Controller

For Mapping from DTO To ViewModel im using the below code, and its working fine.

public ActionResult Index()
{
    ServiceEntity obj = GetData();
    Mapper.CreateMap<ServiceEntity, BusinessEntity>()
        .ForMember(d => d.Details, o => o.MapFrom(x => new ChildBussiness { NameFirst = x.FirstName, LastName = x.LastName, Salary = x.Salary.ToString(), BookDetails = new Books { BookDescription = x.BkDescription, BookName = x.BkName, BookPrice = x.BkPrice }}));

    BusinessEntity objDetails = Mapper.Map<ServiceEntity, BusinessEntity>(obj);
}

While converting back im not able to do. Below code i tried.

.
.
.
ServiceEntity objser = new ServiceEntity();

Mapper.CreateMap<BusinessEntity, ServiceEntity>();
Mapper.CreateMap<Books, ServiceEntity>();

objser = Mapper.Map<BusinessEntity, ServiceEntity>(model);
.
.
.

But i didnt get any success. For an example i provided few properties. I real time i might have more than 30 property. Any suggestion would be appreciated...

like image 397
Vino Avatar asked Aug 01 '13 11:08

Vino


1 Answers

EDIT Thus you can change BusinessEntity implementation, you can use power of AutoMapper conventions and flattening. Here is modified business entity:

public class BusinessEntity
{
    public string FirstName { get; set; } // Instead of NameFirst
    public string LastName { get; set; }
    public Book Bk { get; set; } // Bk instead of BookDetails
    public string Salary { get; set; }
}

public class Book
{
    public string Name { get; set; } // No prefixes
    public int Price { get; set; }
    public string Description { get; set; }
}

You need Bk name to allow flattening of Bk.Name to BkName. Now all mappings will be generated in several lines:

// For mapping from service entity to book
Mapper.Initialize(cfg => cfg.RecognizePrefixes("Bk"));

Mapper.CreateMap<BusinessEntity, ServiceEntity>();

// Trick to un-flatten service entity
// It is mapped both to Book and BusinessEnity
Mapper.CreateMap<ServiceEntity, Book>();
Mapper.CreateMap<ServiceEntity, BusinessEntity>()
        .ForMember(d => d.Bk, m => m.MapFrom(s => s));

That's it. All 30 properties will be mapped by convention:

var service = new ServiceEntity {
    FirstName = "Sergey",
    LastName = "Berezovskiy",
    Salary = 5000,
    BkName = "Laziness in Action",
    BkDescription = "...",
    BkPrice = 42
};

var business = Mapper.Map<BusinessEntity>(source);
var anotherService = Mapper.Map<ServiceEntity>(business);

ORIGINAL ANSWER Thus you are using custom mapping, from service entity to business entity, then default mapping also will not work for backward mapping. You should manually provide mappings for members:

Mapper.CreateMap<BusinessEntity, ServiceEntity>()
    .ForMember(d => d.FirstName, m => m.MapFrom(s => s.Details.NameFirst))
    .ForMember(d => d.LastName, m => m.MapFrom(s => s.Details.LastName))
    .ForMember(d => d.Salary, m => m.MapFrom(s => s.Details.Salary))
    .ForMember(d => d.BkName, m => m.MapFrom(s => s.Details.BookDetails.BookName))
    .ForMember(d => d.BkPrice, m => m.MapFrom(s => s.Details.BookDetails.BookPrice))
    .ForMember(d => d.BkDescription, m => m.MapFrom(s => s.Details.BookDetails.BookDescription));

But I think manual mapping is better in this case, then providing all this maps for individual properties.

like image 111
Sergey Berezovskiy Avatar answered Oct 14 '22 05:10

Sergey Berezovskiy