rehansaeed.github.io icon indicating copy to clipboard operation
rehansaeed.github.io copied to clipboard

[Comment] A Simple and Fast Object Mapper

Open RehanSaeed opened this issue 5 years ago • 22 comments

https://rehansaeed.com/a-simple-and-fast-object-mapper/

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Brent Brent commented on 2019-03-06 17:45:04

What an incredibly well done post! Than you! Ok, I have a question. Normally I presume that during testing, my IOC container or configuration will repoint my SQL Server connection to a more light-weight tool such as SQL CE or LocalDB. You implied that providing sample data, for testing purposes, to SQL CE or LocalDB is difficult in comparison with using EF Core in-memory. Why is that so?

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-03-06 18:42:33

What an incredibly well done post! Than you! Ok, I have a question. Normally I presume that during testing, my IOC container or configuration will repoint my SQL Server connection to a more light-weight tool such as SQL CE or LocalDB. You implied that providing sample data, for testing purposes, to SQL CE or LocalDB is difficult in comparison with using EF Core in-memory. Why is that so?

Perhaps I could have been clearer. There are a few extra problems when you have to deal with a real database, as opposed to an in-memory database:

  1. You have to have a real SQL Server provisioned. This may be simple if we're talking about a developer machine but what about when we run the tests in a CI server? Do you pay for a server just for functional tests?
  2. You need to create the database, database schema and the user needed to connect to the database. You also might need to think about migrating the database (See next item).
  3. You could drop the database and recreate it after each test but that would be dreadfully slow. Instead you should probably look at a tool like Respawn (Another great project by Jimmy Bogard) which clears the database instead making the test a lot quicker. The downside is that now you have to deal with migrations as I mention above.

Even after all this there are downsides. It will still be slower than an in-memory database, a lot more complicated and possibly more costly. On the upside, you have something that is a lot more real-world, so you may catch bugs that you wouldn't catch if you used an in-memory database.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

James James commented on 2019-03-12 14:48:03

This is great. I've been doing something very similar. What I would love to have is a VS extension or tool to autogenerate these mappings.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-03-12 16:02:50

This is great. I've been doing something very similar. What I would love to have is a VS extension or tool to autogenerate these mappings.

That would be a nice extension!

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Jason Jason commented on 2019-03-28 12:57:40

Great article and great work achieving these performance gains! I'm curious, what motivated you to create a new mapper when AutoMapper is essentially the de facto standard in this area? Did you run into performance issues with AutoMapper or were you generally just looking for something more light weight?

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-03-28 13:06:33

Great article and great work achieving these performance gains! I'm curious, what motivated you to create a new mapper when AutoMapper is essentially the de facto standard in this area? Did you run into performance issues with AutoMapper or were you generally just looking for something more light weight?

I used to use Automapper and always found little annoyances with it. I believe the latest version is much improved though. In the end, I just thought, this is way over engineered, I just want to map some properties and I can do that by hand in 30 seconds. It'll be boring but it'll work, be dead simple and fast. I then started to write an interface and a few extension methods to help me write mapping code quicker which resulted in this blog post.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

ali ali commented on 2019-04-06 06:44:49

hi rehan how to resolve this problem when using boxed mapper and DI in my project? example :

public interface IPrepareProduct<TProduct, TProductDto>: IMapper<TProduct, TProductDto> 
{
}

public class PrepareProduct : IPrepareProduct<Product, ProductDto>
{
    public void Map(Product source, ProductDto destination)
    {
        destination.CreatedOn = source.CreatedOn;
        destination.Description = source.Description;
        destination.Name= source.Name;
        destination.FromDate= source.FromDate;
        destination.Id= source.Id;
        destination.InStockCount= source.InStockCount;
        destination.OldPrice= source.OldPrice;
        destination.Price= source.Price;
        destination.PreViewText= source.PreViewText;
        destination.Published = source.Published;
        destination.SKU= source.SKU;
        destination.ToDate= source.ToDate;
    }
}
/*******************************/
public interface IPreparePicture:IMapper<Picture,PictureDto>
{
}

public class PreparePicture : IMapper<Picture,PictureDto>
{
    public void Map(Picture source, PictureDto destination)
    {
        destination.Alt = source.Alt;
        destination.EntityId = source.EntityId;
        destination.EntityName = source.EntityName;
        destination.id = source.id;
        destination.IsDefault = source.IsDefault;
        destination.Order = source.Order;
        destination.Title = source.Title;
        destination.Url = source.Url;
    }
}

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

ali ali commented on 2019-04-06 11:51:42

how to ignore some property in your object mapper ?

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-04-08 16:15:27

how to ignore some property in your object mapper ?

Just don't write the line of code that does the mapping i.e.

destination.SomeProperty = source.SomeOtherProperty;

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-04-08 16:54:53

hi rehan how to resolve this problem when using boxed mapper and DI in my project? example :

public interface IPrepareProduct<TProduct, TProductDto>: IMapper<TProduct, TProductDto> 
{
}

public class PrepareProduct : IPrepareProduct<Product, ProductDto>
{
    public void Map(Product source, ProductDto destination)
    {
        destination.CreatedOn = source.CreatedOn;
        destination.Description = source.Description;
        destination.Name= source.Name;
        destination.FromDate= source.FromDate;
        destination.Id= source.Id;
        destination.InStockCount= source.InStockCount;
        destination.OldPrice= source.OldPrice;
        destination.Price= source.Price;
        destination.PreViewText= source.PreViewText;
        destination.Published = source.Published;
        destination.SKU= source.SKU;
        destination.ToDate= source.ToDate;
    }
}
/*******************************/
public interface IPreparePicture:IMapper<Picture,PictureDto>
{
}

public class PreparePicture : IMapper<Picture,PictureDto>
{
    public void Map(Picture source, PictureDto destination)
    {
        destination.Alt = source.Alt;
        destination.EntityId = source.EntityId;
        destination.EntityName = source.EntityName;
        destination.id = source.id;
        destination.IsDefault = source.IsDefault;
        destination.Order = source.Order;
        destination.Title = source.Title;
        destination.Url = source.Url;
    }
}

You have not outlined the problem. Also, please raise a GitHub issue to get better answers.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

David David commented on 2019-08-07 14:32:46

Hi Rehan,

fan of your work, as always.. In this case, I am looking for any advantages using this approach, over say, DTO Writer, which will auto-generate mappings:

https://marketplace.visualstudio.com/items?itemName=VitaliiIlchenko.DtoCreator

This creates static methods for ToModel and FromModel.

I admit to being a big fan of code generation.

Perhaps I am missing something, as I have only spent an hour or so looking at this?

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-08-07 15:02:18

Hi Rehan,

fan of your work, as always.. In this case, I am looking for any advantages using this approach, over say, DTO Writer, which will auto-generate mappings:

https://marketplace.visualstudio.com/items?itemName=VitaliiIlchenko.DtoCreator

This creates static methods for ToModel and FromModel.

I admit to being a big fan of code generation.

Perhaps I am missing something, as I have only spent an hour or so looking at this?

Hi David,

That's a really good question. This tool looks useful, I've not heard of it before but I've seen another one in the past. I've even thought about building my own once or twice. Questions I would have are:

  1. Does it help when you want to edit a DTO to generate code for new properties you've added, removed, renamed or where you have changed the type?
  2. Does it handle more complex objects that are not just POCO's? Things like immutable types where the only way to create the object is from the constructor.
  3. Does it handle nested POCO's? This is pretty common.

Overall, it might get you started quickly but I'm not sure that it will be flexible enough. Also, one thing that I've never understood is the time saving factor. It really doesn't take long to write a mapper, unless maybe you have lots to do.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

David David commented on 2019-08-07 16:31:05

Hi David,

That's a really good question. This tool looks useful, I've not heard of it before but I've seen another one in the past. I've even thought about building my own once or twice. Questions I would have are:

  1. Does it help when you want to edit a DTO to generate code for new properties you've added, removed, renamed or where you have changed the type?
  2. Does it handle more complex objects that are not just POCO's? Things like immutable types where the only way to create the object is from the constructor.
  3. Does it handle nested POCO's? This is pretty common.

Overall, it might get you started quickly but I'm not sure that it will be flexible enough. Also, one thing that I've never understood is the time saving factor. It really doesn't take long to write a mapper, unless maybe you have lots to do.

Rehan, actually a combination of DTO Writer and this would seem to match most needs:

https://github.com/cezarypiatek/MappingGenerator

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

David David commented on 2019-08-07 16:50:23

Rehan, actually a combination of DTO Writer and this would seem to match most needs:

https://github.com/cezarypiatek/MappingGenerator

In my case, I very rarely only have a small number of classes to map, so generation saves a bit of time, and potentially errors when repetitively coding simple tasks.

For adding properties or something more complex than one-to-one mapping, I would probably just do that by hand. These tend to be the exceptions, rather than the rule, and it is not worth attempting to automate complex logic...

... unless someone else codes it for me ;-)

David

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Ashish Ashish commented on 2019-09-03 10:04:54

How to manage different property name of entity ?

Lets say I have an entity

public class person
{
    public string name {get;set;}
}

public class personDTO
{
    public string personName {get;set;}
}

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Christopher Christopher commented on 2019-09-20 12:20:43

A more extensive example mapping a simple object hierarchy would be really helpful.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-09-23 09:00:46

How to manage different property name of entity ?

Lets say I have an entity

public class person
{
    public string name {get;set;}
}

public class personDTO
{
    public string personName {get;set;}
}

Easy:

destination.Name = source.PersonName;

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2019-09-23 09:20:47

A more extensive example mapping a simple object hierarchy would be really helpful.

Here is a more extensive example:

https://github.com/Dotnet-Boxed/Framework/blob/master/README.md

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Peter Morris Peter Morris commented on 2020-01-01 16:53:34

The problem with manually writing mappers is that you also have to manually write tests for them.

That takes a lot of time. AutoMapper does it for us.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2020-01-01 17:03:30

The problem with manually writing mappers is that you also have to manually write tests for them.

That takes a lot of time. AutoMapper does it for us.

I don't think that code takes very long to write. You still have to write a test if you use Automapper. Docs suggest this:

var config = AutoMapperConfiguration.Configure();
config.AssertConfigurationIsValid();

It checks that every single member has a destination type. It may not be the right one (since there are always exceptional cases), but it at least tests that every property is copied from source to destination.

There are pros and cons. Automapper still has it's uses.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Sam Sam commented on 2020-01-04 13:11:26

I like the direction you went with this. We struggle back and forth with the same person points of automappers as you do. Mostly property references. I want to know what you consider different about your approach than manually mapping (I think you called this baseline)? Yes you are creating a mapping framework with the interface but you are still manually writing the mapping. I am not opposed to manually writing the mapping a because we do that now and it's the most performant, but isn't yours also manually mapping? How is your benchmark time slower?

RehanSaeed avatar May 12 '20 09:05 RehanSaeed

Muhammad Rehan Saeed Muhammad Rehan Saeed commented on 2020-01-04 14:04:54

I like the direction you went with this. We struggle back and forth with the same person points of automappers as you do. Mostly property references. I want to know what you consider different about your approach than manually mapping (I think you called this baseline)? Yes you are creating a mapping framework with the interface but you are still manually writing the mapping. I am not opposed to manually writing the mapping a because we do that now and it's the most performant, but isn't yours also manually mapping? How is your benchmark time slower?

It's really just a set of extension methods to make mapping easier and interfaces to standardise things so developers know what to expect. That's it. Just enough to make manually mapping more bearable and slightly faster to write.

The time is mostly a bit slower because we use an interface and we also use a different method of newing up instances of types as opposed to the new keyword.

RehanSaeed avatar May 12 '20 09:05 RehanSaeed