10 years ago I was working on a large project that used AutoMapper and it became very clear to me then that it was an anti-pattern. More often than not, it creates more problems than it solves.
Like mutations during runtime that cause inconsistencies? Or a bunch of unnecessary boilerplate mapping code that could be handled with a 3 line extension method with a Func param as the mapper/selector?
Most frameworks nowadays seem to contain anti-patterns. I feel it’s because initially they solved a problem but were extended to solve many problems with the same pattern. Everything looking like a nail type development. I’ve now stopped using frameworks, except for the fundamentals from MS and am vanilla all the way. This has resulted in faster iterations with less time trying to figure out why something isn’t working due to framework inconsistencies. Framework fan boys send replies to /dev/null.
I seem to recall that I used it before then in the days of LinqToSQL (prior to Entity Framework) and it caused entire table hierarchies to be pulled from SQL Server with the associate performance penalty. Never used it since on any projects I have been responsible for initiating.
Started 2001-2002 myself. I was forced to use automapper (or some other library, can't remember what) once. I found it really stupid. Configuring the mapper was really confusing and cumbersome compared to just write the mapper yourself. They were both done with C# so I just couldn't see the point in using automapper. Nowadays I bake the mapping inside the models/DTOs/entities - what every you call them. For example FooEntity has method ToFoo() => FooDto. Of course versioning makes it a bit harder but in 99% of cases I have only one version in production.
One big advantage Automapper has over Manual Mapping is that you can set up a very simple generic Tests by calling 'AssertConfigurationIsValid' on your Configuration. This will ensure that all properties in your Target Types are 'taken care of' either by having a implicit/explicit source or an explicit ignore. This way, 2 years from now when Junior #69 joins the project or a different dev has to take over and 'busines just wants him to quickly add a single property' the tests will show that adding this property in the DB-Entity alone is not enough, but also needs to be added in the different DTOs, DB Query projections, Business Entities etc. whatever system you may have.
I agree with this. I use AutoMapper to map Model to ViewModel (and back with ReverseMap) in WPF MVVM and call AssertConfigurationIsValid straight after config.CreateMapper(). (I should write a test though)
Just because you added a property to an entity doesn't mean you need it in all of the related objects. If you DO need it, you add it with a required attribute and the requirement is satisfied at compile time. Blindly adding a new property to every mapped object doesn't make sense at all...
@mihhailmaslakov2908 Agreed, I'm not advocating to have the exact same properties on all Entities. The Test simply makes you aware that there is a potentially problematic situation and that you need to make a decision. You can decide to explicitly ignore it or to map it to fix the Failed Test.
Thank you so much. I agree with everything you said here. I see myself getting frustrated when working with other C# devs who tend to over-complicate things and use fancy tooling while I tend to keep things simple as much as possible. Auto-mapping is definitely one of these things.
In our company, we mostly use an automapper because of the projection of SQL queries, which greatly simplifies the calling code in conjunction with repositories According to our research, no other mapper analogues provide projection functionality
@@tedchirvasiu It does tho, no? I'm pretty sure I saw something like that, it is even in their docs: > IQueryable projections Mapperly does support IQueryable projections: (...)
Or you could just write sql and not have to duplicate your entire db schema into your c#... Seriously, you may as well call rename it to AutoTriggers...
I agree, everyone hates on automapper but then no one provides an equivalent solution to projections which I think is autmappers standout feature for dotnet development. I agree with everything said about keeping mappings as basic/simple as possible, however if I have LargeEntityA and I need to load that into SubsetModelA, B and C for various needs in different parts of the application, then automapper projections saves us from writing a lot of query code that is tedious to write, and equally tedious to update/maintain. Maybe manual mapping works fine for little basic web apps with a handful of fields but if you are working on large data models in enterprise applications then this feature is worth it's weight in gold, and makes using automapper totally worthwhile.
@nzpc2005 actually I have a answer that does the exact same thing. A single, universal extension method: Map(this obj, Func mapper) => mapper(obj). It does projections, when you realize that projections are just computed properties done for you by automapper. I know I just said something that sounds crazy, but if you try to recreate the example on Automappers projection documentation page, using only your custom Map func and (optionally) arrow properties for the view props, you'll understand it completely.
After working with AutoMapper for years, we've migrated to Mapster and here's why: You _can_ use it with no config files. One of the issues I have with "AutoMapper" is that I needed to create all those mapping files, even if they were all using the default mappings. There's a rule on the team that says no custom mappings. Therefore you're forced to use the mapper for the default things (1-1 mappings, flattening, etc.) The beauty of not needing mapping files, is that there's no place to do bad things. If you need something custom, then we build an extension method. The other rule is, only user the mapper for goin from Domain to DTO, never the other way around (too many changes of things getting nulled out where you didn't intend). These rules have resolved the vast majority of AutoMapping issues.
We have a project with about 50 classes that can all be serialized and written to a file. Overtime we started getting backwards compatibility issues as the older saved files were out of sync with new versions of these classes. We ended up introducing a serialization layer that handles mapping older properties to the correct new ones. We deliberated between custom mapping and using AutoMapper and in the end decided on AutoMapper. It was simple to set up, especially for the 80% of the classes that had no backwards compatibility issues, and allowed us to inject some needed services into the mapping without having to write our own custom mapping framework. We had a team of junior devs at the time and we found it easier to teach them AutoMapper than to have them write that custom framework. Our project already has pretty good unit test coverage so of course we added tests for the mapping as well. We haven't had any issues with the mapping at all. I can see why you wouldn't want to use it, but I think it's saved us time and the client has been happy they haven't run into backwards compatibility errors in a long, long time.
"Anything that moves compile time errors into runtime errors should be discarded." I generally agree. But doesn't this also mean to stop using DI frameworks?
If you use DI, stick to DI, don't mix it with other patterns because it will defeat you in almost any scenario where you need use more that couple classes in your project.
To me the difference is that with DI you will get the runtime error the first time your run your code, but with automapping errors can be tricky edge cases that wait for production to bite you. Also, the benefits of DI are so great, it is worth it; not so with Automappers.
I'm not against of mappers and I still use them in my projects. But I totally agree with the first comment (compile vs runtime errors). So, I've switched from AutoMapper to Mapperly which is a source generate based mapper. It is capable to detect some errors like unmapped property, required properties, or something else. I do not add any logic to mappers and manual code looks like a lot of boiler plate code, so I can generate it.
I inherited a project using a lot of AutoMapper (from database models to json models and vice versa, from database models to view models and vice versa, etc) basically all object transformations were done using AutoMapper. Honestly, it's been nothing but bugs. I had a situation where it was implicitly mapping an object into a string that was not even used anywhere and the only error I saw was a null reference exception sometimes, took me a full day to track that one down. I abhor implicit behaviour and runtime errors and since moving to .NET 8 I've just been changing everything to records, using the required keyword, and everything has been so much simpler. AutoMapper seems to me like a solution for a situation where you have objects with a million properties that are mostly the same, but that's not how you should be fixing that, and while it may reduce the total amount of work for a fire*and-forget project, any project that is actively worked on will pay interest on that and end up being more work than just manual mapping.
I worked on a classic n-tier project once many moons ago and they insisted on creating a version of the data objects for each level of the system. The API had their viewmodels, the business layer had business objects and the data layer had the EF data models. AutoMapper was plumbed in at every level to convert the data objects back and forth as data flowed up and down the layers! It was crazy and so annoying! Imagine calling a getuser api, that calls a getuser() function on a business layer user service that called a getuser() function on a repository. The repository the wrapped around EF would return a DB User object to the user service, that automapper would convert to a BL User object to return to the controller that would then user automapper to convert to a ViewModel User object to be returned to the frontend!
I have recently joined a project where they are doing just that! My understanding is that mappers that map at runtime do it using reflection. When large numbers of records are concerned, that is a massive performance hit. You wouldn't use it in high performance scenarios.
The fact that people are doing too much with it doesnt mean it doesnt serve its purpose.. it's awesome in generic code for many reasons.. now i could write my own simple generic automapper that does the same... but i dont see the point.. it's good enough and simple enough for my need.. it need way less maintenance than manual mapping..
Manual mapping, though not with extension methods, as those may pollute IntelliSense suggestions too much - I simply use a static class as a "namespace" for mapping methods I forbade my team from introducing AutoMapper in projects I inherited, and I'm vocal about it whenever I encounter it in other projects. However, I realize that my experience (a decade ago) is simply not transferable. I presented several reasons not to use AutoMapper, but no one ever listened. I'm happy to see you spreading this "idea"; hopefully, more people will listen to you. 😊
Apart from all the issues mentioned… No one needs all that extra maintenance of maintaining a third party dependency that proliferated throughout your entire codebase. We have the simple mantra: “Minimise 3rd party dependencies“.
As I also pointed out in the post on Reddit, there are deeper problems in your architecture if you're reaching out for a mapping solution. Extension methods for sure are the way to go if you absolutely need to, but you should also re-consider what you're doing with your classes if you're finding a 1-1 relationship with many of your properties. Your contracts/DTO/queries/whatever you want to call them just might be very bloated and unclear in their purpose. It's an apt time to rethink why this yak-shaving step is so necessary in your architecture. It's the same problem with microservice vs. monoliths. The problem is the intentionality of your code, not the logistics of moving data around. Leave that for performance optimization.
Sometimes it is not a problem with the architecture per se, but with the external tooling. It is not an easy feat to do very strict and behavior modeled C# objects play well with ORMs for example (which in turn leads you into needing the separation between your business models and your data storing entities) or even to respond to common user requests that requires only a very small subset of properties from a larger query (which is common in many more complex products). There are times you can hardly avoid mapping solutions, and I don't think your generalistic advise is a good thing.
EF projection is the only thing I use AutoMapper for. Maybe this is the best use for AutoMapper? I have no problems and my code feels clean and organized. He talks about not using Mapper for anything else and not to include logic in it, but I don't quite know what he's using if it's not a mapper? He said he builds extensions methods at 3:07 like MapToDto..? I guess that would work but Mapper and EF just work so well together why bother.
AutoMapper helps a lot to catch mapping errors. Imagine you have an entity and DTO. At some point in time, you need to add one new property or two. You add them to DTO and entity, but forget to modify the mapping method. You end up with a bug report from the customer. Here is what we do: We write a single unit test, which creates an instance of IMapper followed by adding all mapping profiles using assembly scan. Then we call AssertConfigurationIsValid. Test will fail if you have unmapped or incorrectly mapped properties. With CI configured to run unit tests, you get your application mapping tested early.
4:02 the passion displayed here is how i feel about these things aswell! Move as many things to compile time as you can, therefore use mapperly a source generation mapper, use strict mapping to ensure you never miss a mapping again (this is a benefit over manual mapping) and turn those warnings into errors with your .editorconfig or the likes.
Always write your own mappers. If they use a mapping library internally, then that's an implementation detail and the rest of your code should not be aware of it. If you have a "special case", then skip the library and write that one manually, but the consuming code should be none the wiser. The advantage of using a mapping library IN your mappers is that when someone adds a new property, you don't have to rely on an easily distracted human to remember to add it to the mapper by hand. You get to code just the exceptions.
@@PeriMCS I've been burned by the easily distracted human leaving off the new property more often than I have by AutoMapper being cumbersome. I'm all about the Mapperly now. Compile-time checking and automatic inclusion of new properties as long as they're simple. It gets me 90% of the way there, and I can handle the remaining 10%. I'm still going to hide it inside a concrete mapper class, though, so I can fully take over any time I find a weird case.
@@PeriMCS Something to do with 8r ? In some environments where I have worked, they worship that library but it is a pain in the *arse because intellisense, 'Goto Definition' and 'Goto Implementation' can't handle it. Likewise, if you want to debug a command handler, you have to know which handler to debug and place a break point in it because debugging doesn't step into the handler code.
9:05 Yep, it's like the slippery slope of OO hell I always see in Java projects with ObserverIteratorFactoryMapperClientProducerContext type abstractions. Working on a large project for years all of those clever things you come up with you will literally forget then you have to relearn everything you did. Keep it as simple as possible always and it will usually be the best solution in the long run.
@@tedchirvasiu Expressions are supported, it is in the docs. But I also think that you can circumvent that temporary limitation without much hassle anyways.
In our current project, we try to avoid external libraries the best we can. Because every library needs a certain amount of attention (MEND warnings because of vulnerabilities etc) and produces maintenance costs. Hand-written or Copilot generated mapping methods are easier to debug, easier to read, faster. Just fire-and-forget.
I like a simple IMapping interface that has a TTo Map(TFrom), and that's it. I can DI, reuse it, I might have some frequently used enums that I want to translate between, and its just doing the one complex thing. If its super-simple, extension method, static mappers and whatnot is fine, but now and then it might be a little more complicated than flat entity to flat DTO and reverse. If you ever have the misfortune of working with UBLs, you will not be happy with anything
If you use automapper as intended and only as a mapping tool, then it does saves heaps, though it did make me do a double take where object hierary was mapped uaing conventional name based mapping Recently have started using source generator mapperly
Challenge accepted. "Fixed" my code and removed Automapper. It wasn't difficult using extension methods. But honestly, not seeing a savings in terms of maintenance. Agree that runtime errors avoided will be worth it. I think there is room for Automapper in the prototyping phase, or early stage, of a project. It's a well written useful tool and I'll still use it when it makes sense.
Thanks for this video, I have been arguing against mappers for 10 years for these reasons and because it also hides the dependency between classes, especially in lazy usages where you do not setup the mapping in advance but use it adhoc. Having this video to point to will be helpful :) Yes there are some cases where a mapper is useful and do not add problems, like mapping from a DB where you just name the properties the same as the field (even if today I would mostly use dapper or some similar ORM solution, but thats still a mapper), since in that case there are no compile time connection between the sql query and the class anyway. You can use Entity framework for that and get a compile time mapping but that is not always the best solution for more extreme databases. And the extension method is also my goto solution in most cases except when I have many sub projects and there is a risk that you just did not include the right namespace. In those cases I have used a static method on the actual data class, I know this looks bad, but it ensures that the conversion method can be discovered by a developer unfamiliar with the code base. I prefer the extension solution since it keeps all such logic separate and as long as you have a common "conversion" namespace it should not be a problem. Anytime you need logic, then its not a mapper and you should use a factory, transformer or some other solution that explicitly indicates that its not just a mapping but something more. Having something look like a simple mapper that under the hood makes an sql query to add more data and then have another unsuspecting developer use the "mapper" on the 100 000 row result set, tanking the server, is not the best way to learn why its bad (might be the most efficient learning way, but with a high cost)
Real question: if you have manual mapping, how do you handle mapping expressions over the mapped entities? Specifically, if the backend is Entity Framework, you cannot simply couple the expression with a projection to the mapped types and still get a reasonable compiled SQL query.
Shouldn't a mapper just 'map' ? If it is performing any kind of expression evaluation or conversion, then it isn't 'mapping'. And if Entity Framework is doing projections, isn't that a form of mapping - why are you double mapping with AutoMapper ?
@gppsoftware I am not double mapping. I have an endpoint that exposes data using the OData protocol. That means calls to the endpoint yield an IQueryable of TContract, meaning an expression. If the mapping from TContract to and from TData is done manually, how do you propose converting IQueryable of TContract to IQueryable of TData? I've tried writing an expression conversion visitor, but that's REALLY manual and cannot leverage the manual mapping well. We've used AutoMapper for this, and it works... ok-ish. It does the job mostly but has a lot of cases it does not support.
@@jamesterwilliger3176 Easy. `IQueryable ProjectToB(this IQueryable q) => q.Select(i => new B { One = i.One, Two = i.Related.Two, Three = i.Related.OneMoreRelated.Three });`
I never really understood what mappers are good for. Until I was working on a project where automapper was used and it was helpful. Maybe we were lucky to only use it for simple mapping (and a few easily understandable complex ones, but 99% were simple and the fact that it worked out of box was helpful). I'm not sure whether I would choose any mapper library for a new project, but I can see the value when used correctly.
I LOL’ed with the “password encrypted in the mapper…Jesus Christ, what the hell!?” Well-said and thank you Nick. I 100% agree with this. I’d rather struggle with the less complexity of manual mapping of even a large class rather than chase down the invisible runtime issues and scattered mapping logic that ensues when using automapping libraries / services.
Good video! I use manual mapping as well. However, the only thing that makes me use AutoMapper still is mapping expressions using the AutoMapper.Expression library. Because expression mapping, oh my god is difficult.
4:07 You can also easily make a general extension method and use an interface with for example an abstract static method to generalize your mappes, so you can do things like: query.MapTo() and list.MapTo() with ease and without needing to create many extension methods in your projects.
@@z0nx Nop, you just need some generic constraints and it is all good. I think this website don't like when I paste code as it hides my comments, so it is hard to give an example, but look into "generics" (for the basic construct on the language), then "static abstract interface members" (for having access to static properties and methods of types) and normal "generic constraints" for specifying which interfaces your types need to implement in order for a method to be callable. Then look into the concept of "extension methods" and you can just mix those and make a good, fast and reliable extension method that will enable you to make your code more concise.
@@NickTheCodeMechanic I think people have a hard time putting together many of the C# concepts (like generics, constraints, static members on interfaces, extensions and all) to come up with interesting ideas, but if this I said can help someone I'm already happy. I'm also looking forward to the new extensions feature of C# (if/when they release it) as it will (I hope so much) solve one of the biggest painpoints of extensions right now (which is, you cannot have partial type inference in C#, so if you want to have the first generic argument be inferred and the others be explicit you are out of luck).
@@diadetediotedio6918 I know all those concepts, I just wonder why you would use this for mapping. Why use an interface? So you can have multiple implementations? We are talking about mapping right? The same kind of code that nick mentioned that should be as simple as possible.
6:55 Mapperly also allows for easy escape hatches from the library, which kinda solves the problem for the 80% of the cases but let's you do the 20% a bit more complex. This is already a good balance instead of needing to do it all manually.
I stopped using AutoMapper about two years ago. At first, I wrote everything manually, but after I came across Mapperly, I use it for simple mappings. If the mapping is really complex, which I try not to allow in my code, then I write the mapping by hand, since in this case more control over the mapping process is needed.
Write it by hand and use a .Map(this T obj, func mapper). Extension method, so you can easily chain your mapping... Don't forget to return T after performing the Func...
I think, I've found the best scenario (for me at least). Mapperly-generated extensions + custom extensions. All simple enough logic is done by Mapperly. Moreover, Mapperly can raise compile-time errors (warnings actually, but you can treat them as errors) and help you to avoid many mistakes. And if Maperly itself is not enough - you are free to create extra extensions. You can even combine Mapperly-generated and custom logic. That is so convenient!
Same here - got rid of all automapping and moved to manual since it made a lot more sense and also much more simple for our juniors to understand. While the idea is cool it complicates everything to a point where when running massive apps with a lot of edge cases it becomes an absolute nightmare to deal with! No automapping EOD 👀🙈💗
EF is the same way. One of the companies I left used it and kept writing all sorts of 'filters' for the main dashboards table everywhere in the codebase. It was 8 year old code and 8 layers of spaghetti hell. All to filter a bloody table. Datalogic. That was the parent company.... I wanted so bad to simplify the code, but there was no documentation to speak of and their Sr dev quit for that reason, and the lack of solid direction in the project. Hairiest code base I ever saw in my life. The SQL 'config logic' was a like 5 separate sql files, each thousands of loc long filled with insert into over and over. No json or anything... no,we can't have that! And 5 different tables I think, just to update a simple key value pair (i forget what for) in the db (oh wait, right, it was undocumented, so I never knew whag it was for! My bad).... I was fired after trying for a week to figure the code out. 3 weeks prior, the laptop ate itself alive thanks to windows 11. Idk why, but soooo many "Microsoft shops" are full of this kind of incompetence. Idk how it's so hard to run sql and turn it into HTML. Really, is it so hard? 😠 😡 👿 😤
Automapper is cool with GraphQL (HotChocolate) though, because it maps projections. Select fields from an API model, map to entity, your query is rewritten correctly into SQL, map back
I would prefer to write "smart" tests (like using reflection to check if all properties are present on both sides) and keep the mapping function simple. Compiler helps, but it is not enough to enforce design and contracts.
Hello, just wondering how would you resolve our case. We use custom datetime converter inside mapper, and in your approach we will need to pass a converter inside extension method or add one more layer to do this time convert
I only used AutoMapper in one of my projects. Enough to know I will never use it again and it's still a pain in the ass to maintain. I actually do the same thing Nick talks about, an extension method. Super simple and intuitive, also extremely easy to maintain.
i agree with most comments, but you said writing custom mapping is fine.. what would you do when you have to map 100s of fields? or maybe map a master and detail data where each has 100s of fields? that's defintely not a 2 minutes job.
Now I remember, I was on a project with a LOB app, WPF, and they have had consultants working on project basis on this. So many different styles of coding based on the developers understanding of MVVM. A lot of legacy code. But the AutoMapper configurations were set inline in views - that were hard to locate. And that made it harder to see how it mapped object. So the down-side, if we ignore reflection, is debuggability, especially when the mappings are not obvious. I very much prefer to write my own manual mappings nowadays.
When I am going trough code that uses automapper, i always find it confusing how objects are being translated while manual mapping makes it clear and very simple. So I always try to steer away from it. I even had this discussion yesterday with colleagues, so I will be using this video :)
Pro Tip: Write your manual mapping code as expressions! Expression Map(...) Then you can use them to project results from database into your DTO or whatever result object already on DB layer. This way you will avoid bringing unnecessary information from DB into program's memory, therefore solving the "over selecting" problem. ;) (If you insist using mappers, AutoMapper, Mapster, Mapperly, whatever, then those can also produce expression mapping... If you insist.)
I really like this idea! It can decouple the mapping code from the type, allowing you to specify mappers with far more flexibility and explicitly, improving visibility also.
@@GigAHerZ64 I've been chatting with multiple generations of ChatGPT and Claude to figure this out to no avail. How do you call the function in the nested mapping?
I write my automapper code as expressions. This tip isnt really tied to mapping, though. Fetching code using an expression is recommended instead of fetching all the fields and then picking what you want.
Negative value of mappers is quite clear. But if we consider Mediatr, don't you think it's overhyped and does not bring real benefits for Web API projects? (Unless you really need and actively use mediator design pattern for something)
I prefer manual mapping for control. And I often add a property that needs business logic and with manual mapping it's easy to customize. And mapping is something we just do once and seldom change, so not much time to save imho.
We use AutoMapper in a niche of our modular monolith. We have one legacy application that forces pretty dumb models upon us in a SOAP API and we remodel it into something useful and expose it in a REST API. Thats where Automapper is pretty strong, its simple mappings, barely to no logic at all and it saves us a bit of time writing our own mapping code. Other than that I agree, I wouldnt use a library when you can just write your own static extension to map into something else. Just makes debugging things a lot easier
Which, if you think about it, is another project in itself....one you don't control and have to obey a specific paradigm in order to squeeze out a tiny drop of benefit from...
@@NickTheCodeMechanic We do almost everything by hand insted of using libraries. Too many times have we been smacked on the butt because something is deprecated and we had to rewrite it from scratch anyway. We use nugets from microsoft (which can of course also be deprecated) and some inhouse nugets that we have control over but thats it. In my personal projects i like to try different nugets for fun, but it does not feel reliable to use them in a work setting with real production code
Code generation is a good middle ground. Now your exceptional cases are at generation time, thankfully most libraries that do this kind of thing tend to have good stack traces and docs.
There was a moment when the best mapping solution was a code generation plugin to visual - or generated mapping template, you could change it to whatever you want Now in fact it was superseded by the copilot
AutoMapper is a pain in the rear. I've never once voluntarily worked with it, but unfortunately I have certainly come into contact with it plenty. Code bases where they probably started with 'map from [prefx_FieldName] to [FieldName]' or something. Easy enough right, mapper it is. The problem is that those people that use it generally end up with totally convoluted profiles due to it never quite turning out that simple. After all, sometimes we end up with fields that don't match in name, fields to ignore, custom stuff for certain fields, dual direction mapping, etc. I've ended up in projects where the AutoMapping was really some giant black box, using multiple profiles, mapping in multiple directions, and you had no friggin clue what the heck was going on anymore with all that profile shizzle. And since you don't actually have code to set a breakpoint, you're kinda up the creek without a paddle. WORSE YET, the 'upgrade experience' on that library has been a total nightmare over the years. I get it, the DEV wants to optimize and improve as time goes on. But upgrading those stupidly complex implementations pretty much amounted to a full rework, trying to figure out how to get it rewritten in the new version due to a ton of breaking changes.
What could make sense would be an extension for Visual Studio, which the user would pick two classes in the Solution Explorer, and then open an Wizard "Generate Mapping".
I used to write my own mappings because I did not know about the existence of mappers. Then I found out about them and asked myself: "Well isn't this overcomplicating things? Isn't this trying to generalize something not really generalizable? Why does this even exist?". Well, well, well ...
I've been using automapper since it came out and never liked it! The main reason I see to use it is because it often seems to be the least painful solution at the time... emphasis on the word "seems", there are definitely projects that I have worked on where automapper was a major source pain! I guess I could give an advice like keep you implementation of automapper simple but that defeats some of purpose of having a fully feature software tool... There is always manual mapping... but that's the initial pain I'm trying to get rid of :(
It’s a trade off like everything else. I think AM made sense as a feedback loop for unmapped fields in older versions of .net but with init/required keywords there is now a built in feedback loop with manual mapping code. Adding those keywords is want made AM no longer a good trade off
I use Mapster. It's initialized as a part of a static class which contains it's instance. When doing "regular" mapping, invoke mapster. When I need something special, I add a static method. Problem solved, best of both worlds.
I don't hate AM, I just realized, if you need to map something, there should be compilation-time mapping generation, later, I realized that I don't need mapping at all. So, I completely stopped using it in my old XF-based application for new features in the project. My primary concern was a performance one.
The biggest mistake is to stubbornly stick to one method and complaining about drills being unable to screw the nails in. Use damn the hammer if it's suitable. Just do thin wrapper and treat auto mapping as implementation detail. You can switch to suitable method there, auto or manual becomes a mere detail.
But how to find all extension methods, if your domain class will be extended with a new property? Quite often this new property you need to map to all responses and DTOs
I stopped using AutoMapper a few years ago, best choice ever. Runtime errors instead of compilation errors, poor performance, a lot of magic sometimes. Just map it manually, it’s not hard, we have tools to help with that, it will be easier to maintain and reason about and it’s one less dependency to worry about.
Another ding against automapper is the amount of memory it uses. The guys who first wrote the app I currently work on, I swear automapper paid them a nickle for every time they called the method. Most models go through 3 mappings in our "backend' project (sometimes more, occasionally less), and most of that goes through our "BFF" with 2 more mappings, before going to the client. Automapper profiles take up a couple hundred MB of RAM.
I mostly just use a generic method that maps properties with same name and type automatically with reflection. I also have two custom attributes I use to annotate properties where names differ, either MapTo or MapFrom. It's like 30 lines of code. Works just fine for me. Don't need anything more complicated.
AutoMapper should be kept simple. It is great for domain to dto mapping with no, to minor conversions/translations (Class to class mappings). Mocking auto mapper is also going to miss issues.
I use implicit mapping to convert between domain entities and request models, ef core expression mapping to convert from domain entities to DTOs, ever since never used mapping libraries.
I disagree with the position that a mapper cannot have dependencies. In some projects where the SPA frontend needs to display the current user permissions, the easiest way is to inject the AuthorizationService and return to the user what he can do with the current entity.
2 วันที่ผ่านมา
The moment you do something a little bit complex in a mapper, you are doing it wrong. The only place where I think they have a large benefit, is when there is added a field/property on either the from or the to, and a UnitTest or startup Validation can pick up a missing mapping. If I could get an analyzer that picket this up, I would not see any benefit with mappers today. I do like Mapperly the most, but I did have an issue with one version when using Rider (but not in Visual Studio). But at least with Mapperly it's easy to migrate away from it.
I actually like this take, i've used Mapster a lot and though it really makes a lot of stuff super easy, it has also sometimes been a huge pain when stuff i not working as expected and it does sometime make it feel very "magical". How would you go about Many to One mapping? Tuple? Parameters on your mapping extension?
This screams more of a change in fad than actual practical advise to make things better. I've used AutoMapper in quite a few projects and it has worked wonderfully. I prefer the IMapper interface to spreading extension methods out all over the place. It does a lot of nice things we use.
Mapperly looks promising, I will check that out. Other than that, in my whole career I tried to avoid using Automapper as much as possible, due to the already-discussed topics here.
In my project we use Automapper, but we try to not hide logic in the mapping. We have a lot of entities mapped to Dtos that are almost exactly the same so it helps a lot. The thing with manual mapping is that, if the mappings are not centralized in a single place, you may forget to update a random mapping when you add a new property to your entities, and when you centralize the extension methods in a single file, it becomes a bit messy (MapToDto, MapToCreateDto, MapFromDto, MapFromCreateDto, etc.). The bad part is that you only know that you missed a mapping after testing it.
Mapperly is "better" in the sense that the mapping errors are exposed at compile-time instead of run-time. But the generated code is still out of sight, out of mind. Omissions in mapped fields won't be obvious at all until you run the code and data just isn't present. I just don't really understand the need to generate mapping code in the first place: Mapping code tends to be easy to write, easy to test, and gives you complete flexibility to evolve models in different layers independently without having to worry about whether the mapping library can figure out how to map one to the other.
with the introduction of chat-gpt there is absolutely no point in using automapper. complex cases were a pain to manage to begin with, introducing errors that took hours to find. It was mostly used to not waste time mapping classes to dto's 1 to 1. Now, you can just make chat-gpt, copilot, cursor generate the mapping code for the simple cases and handle the complex ones in your own code-base, making it easier to maintain.
Jimmy might be upset. But wonderful video. Long needed. Why did nobody say this before. Like the emperors clothes. I do not love extension methods, for similar reasons. Mapperly sounds like a win.
I am using automapper, very little custom code added. And it is working just fine, it does the job... however i would like to have one where i can see more clear the properties mapped, and what happens on a rename.
I was totally against automatic mappers till I ended up having to fix tons of DTO mapping issues by devs who copy-pasted manual mapping incorrectly leading to incredibly hard-to-find bugs because they didn't add proper testing. And even in cases where they did add tests, they simply copy-pasted bad property mapping into the tests themselves which was even worse. At that point I realised the value of automatic mapping libraries. Since I've started using them I've experienced far, far fewer issues related to mapping then before. However, unlike this video I'm certainly not dogmatic about it. Mapping libraries are tools just like any other. It's all about understanding their use-cases, utilising their strengths and mitigating against weaknesses.
I once worked on a project where the auto mapper configurations had a lot of ignores defined and I thought how stupid is that I am reading what we don’t want to map instead of reading what we want to map.
I've worked at several places where mappers are used and I don't like them. OK sure you are mapping a DTO to or from some domain object and it seems perfectly nice to think that passing the two through mapping will give quick results. My issue is that you cannot be sure what will happen if a new property is added or if for some reason you want to rename a mapped property. If the code is written by hand then you might find you miss a property but good unit testing should reveal this and I'd also say that when I've done this lately, tools like Visual Studio seem to understand what you are doing and propose to complete it line by line and I'm sure AI or a dedicated mapping code builder will take that even further.
What you mean? We know exactly what will happen, the info will not be populated if the properties dont match. If they match but are of different types, it will throw an error.
@shadowkras It depends on what rules are set for the auto mapper. If you are unfortunate your unit tests may pass but then some user enters a valid value that doesn't map.
@@shadowkras Absolutely but would you create that validation by hand? If not then we are simply back to square one because the code that generates it can still be wrongly configured. I really do think there is scope for a type of automapper but for me it might be part of the development environment prompting the developer when changes are made to the mapped objects. Suppose I add a new field to the application layer object called perhaps UserIdentifier and this should map to UserID. We can detect these changes and be prompted to link them. These could be visual in the development environment or output as warnings or errors for the developer to review. Then the validator can also be updated to ensure correct behaviour.
@@NickAskew What you mean create validation by hand? Is there any other way to create validation? You need to tell the code to validate a property and how it should be validated. There are dozens of ways and tools to do it, but you still have to do it "by hand".
myViewModel.Map(MyDto obj); myDto.Map(MyViewModel obj); That's what I end up with a lot of times and do manual mapping inside. And yeah, AI auto generating makes things super fast. If you can't use AI, then use Mapperly if it's simple, do it manually if it's complex.
my problem with automapper is absence of async and after version 11.0.1 there was one breaking change that i rly dislike: classA a = null; classB b = new(); mapper.Map(a, b); 11.0.1 b is null after that b is unchanged also automapping is fine until somebody else wants to change something in your code and trying to find where is some property used, even though that property is mapped to another with same name in different class, you will not find it by "Find all references" This is why i am going to try mapperly next time i want to use mapping (source generated mapping) in my mind it should bring best from both worlds, i do not have to type simple mapping every time i add properties but also should give me opportunity to use async and Find all references will work, this way i don't see need to completely stop using any kind of mapper
We miss trade-off here. When project is evolving we make more issues with manually mapping, from forgetting to map to mapping straight incorrectly. I’ve seen bugs in production like that. Code generators are better solution.
We mock AutoMapper but not in the programmatic sense
😂😂
burn
@@sprez 🤣
10 years ago I was working on a large project that used AutoMapper and it became very clear to me then that it was an anti-pattern. More often than not, it creates more problems than it solves.
Like mutations during runtime that cause inconsistencies? Or a bunch of unnecessary boilerplate mapping code that could be handled with a 3 line extension method with a Func param as the mapper/selector?
Most frameworks nowadays seem to contain anti-patterns. I feel it’s because initially they solved a problem but were extended to solve many problems with the same pattern. Everything looking like a nail type development. I’ve now stopped using frameworks, except for the fundamentals from MS and am vanilla all the way. This has resulted in faster iterations with less time trying to figure out why something isn’t working due to framework inconsistencies. Framework fan boys send replies to /dev/null.
I seem to recall that I used it before then in the days of LinqToSQL (prior to Entity Framework) and it caused entire table hierarchies to be pulled from SQL Server with the associate performance penalty. Never used it since on any projects I have been responsible for initiating.
Been coding C# since 2001; have never used an automapper. The concerns you shared here are important; thanks for sharing.
Started 2001-2002 myself. I was forced to use automapper (or some other library, can't remember what) once. I found it really stupid. Configuring the mapper was really confusing and cumbersome compared to just write the mapper yourself. They were both done with C# so I just couldn't see the point in using automapper.
Nowadays I bake the mapping inside the models/DTOs/entities - what every you call them. For example FooEntity has method ToFoo() => FooDto. Of course versioning makes it a bit harder but in 99% of cases I have only one version in production.
One big advantage Automapper has over Manual Mapping is that you can set up a very simple generic Tests by calling 'AssertConfigurationIsValid' on your Configuration. This will ensure that all properties in your Target Types are 'taken care of' either by having a implicit/explicit source or an explicit ignore. This way, 2 years from now when Junior #69 joins the project or a different dev has to take over and 'busines just wants him to quickly add a single property' the tests will show that adding this property in the DB-Entity alone is not enough, but also needs to be added in the different DTOs, DB Query projections, Business Entities etc. whatever system you may have.
I agree with this. I use AutoMapper to map Model to ViewModel (and back with ReverseMap) in WPF MVVM and call AssertConfigurationIsValid straight after config.CreateMapper(). (I should write a test though)
Just because you added a property to an entity doesn't mean you need it in all of the related objects. If you DO need it, you add it with a required attribute and the requirement is satisfied at compile time. Blindly adding a new property to every mapped object doesn't make sense at all...
@mihhailmaslakov2908 Agreed, I'm not advocating to have the exact same properties on all Entities. The Test simply makes you aware that there is a potentially problematic situation and that you need to make a decision. You can decide to explicitly ignore it or to map it to fix the Failed Test.
Thank you so much. I agree with everything you said here. I see myself getting frustrated when working with other C# devs who tend to over-complicate things and use fancy tooling while I tend to keep things simple as much as possible. Auto-mapping is definitely one of these things.
In our company, we mostly use an automapper because of the projection of SQL queries, which greatly simplifies the calling code in conjunction with repositories
According to our research, no other mapper analogues provide projection functionality
Exactly! I tried switching to Mapperly, everything was great until I found out it does not support Expressions.
@@tedchirvasiu
It does tho, no? I'm pretty sure I saw something like that, it is even in their docs:
> IQueryable projections
Mapperly does support IQueryable projections: (...)
Or you could just write sql and not have to duplicate your entire db schema into your c#...
Seriously, you may as well call rename it to AutoTriggers...
I agree, everyone hates on automapper but then no one provides an equivalent solution to projections which I think is autmappers standout feature for dotnet development. I agree with everything said about keeping mappings as basic/simple as possible, however if I have LargeEntityA and I need to load that into SubsetModelA, B and C for various needs in different parts of the application, then automapper projections saves us from writing a lot of query code that is tedious to write, and equally tedious to update/maintain. Maybe manual mapping works fine for little basic web apps with a handful of fields but if you are working on large data models in enterprise applications then this feature is worth it's weight in gold, and makes using automapper totally worthwhile.
@nzpc2005 actually I have a answer that does the exact same thing. A single, universal extension method: Map(this obj, Func mapper) => mapper(obj).
It does projections, when you realize that projections are just computed properties done for you by automapper.
I know I just said something that sounds crazy, but if you try to recreate the example on Automappers projection documentation page, using only your custom Map func and (optionally) arrow properties for the view props, you'll understand it completely.
After working with AutoMapper for years, we've migrated to Mapster and here's why:
You _can_ use it with no config files. One of the issues I have with "AutoMapper" is that I needed to create all those mapping files, even if they were all using the default mappings.
There's a rule on the team that says no custom mappings. Therefore you're forced to use the mapper for the default things (1-1 mappings, flattening, etc.)
The beauty of not needing mapping files, is that there's no place to do bad things.
If you need something custom, then we build an extension method.
The other rule is, only user the mapper for goin from Domain to DTO, never the other way around (too many changes of things getting nulled out where you didn't intend).
These rules have resolved the vast majority of AutoMapping issues.
Do you have ever tried to use mapperly?
We have a project with about 50 classes that can all be serialized and written to a file. Overtime we started getting backwards compatibility issues as the older saved files were out of sync with new versions of these classes. We ended up introducing a serialization layer that handles mapping older properties to the correct new ones. We deliberated between custom mapping and using AutoMapper and in the end decided on AutoMapper. It was simple to set up, especially for the 80% of the classes that had no backwards compatibility issues, and allowed us to inject some needed services into the mapping without having to write our own custom mapping framework. We had a team of junior devs at the time and we found it easier to teach them AutoMapper than to have them write that custom framework. Our project already has pretty good unit test coverage so of course we added tests for the mapping as well. We haven't had any issues with the mapping at all. I can see why you wouldn't want to use it, but I think it's saved us time and the client has been happy they haven't run into backwards compatibility errors in a long, long time.
+
Paid Automapper shill.
jk, I also use AutoMapper. I tried switching to other mappers, but nothing was as complete and flexible as AutoMapper.
"Anything that moves compile time errors into runtime errors should be discarded."
I generally agree. But doesn't this also mean to stop using DI frameworks?
or maybe try Pure.DI ;-)
@@VoroninPavel impossible if you use any sort of library, none of them do pure di :
If you use DI, stick to DI, don't mix it with other patterns because it will defeat you in almost any scenario where you need use more that couple classes in your project.
To me the difference is that with DI you will get the runtime error the first time your run your code, but with automapping errors can be tricky edge cases that wait for production to bite you. Also, the benefits of DI are so great, it is worth it; not so with Automappers.
@@z0nxwell, you'll need some customisation, but it's still possible
DevTeam/Pure.DI/blob/master/readme%2FWebAPI.md
I'm not against of mappers and I still use them in my projects. But I totally agree with the first comment (compile vs runtime errors). So, I've switched from AutoMapper to Mapperly which is a source generate based mapper. It is capable to detect some errors like unmapped property, required properties, or something else. I do not add any logic to mappers and manual code looks like a lot of boiler plate code, so I can generate it.
One thing I like about AutoMapper is that you can use ProjectTo. How would you do this if you are manually writing your own mapTo extensions?
The extension would be on IQueryable
And you'd write the .Select(x....) method
I inherited a project using a lot of AutoMapper (from database models to json models and vice versa, from database models to view models and vice versa, etc) basically all object transformations were done using AutoMapper. Honestly, it's been nothing but bugs. I had a situation where it was implicitly mapping an object into a string that was not even used anywhere and the only error I saw was a null reference exception sometimes, took me a full day to track that one down. I abhor implicit behaviour and runtime errors and since moving to .NET 8 I've just been changing everything to records, using the required keyword, and everything has been so much simpler. AutoMapper seems to me like a solution for a situation where you have objects with a million properties that are mostly the same, but that's not how you should be fixing that, and while it may reduce the total amount of work for a fire*and-forget project, any project that is actively worked on will pay interest on that and end up being more work than just manual mapping.
I worked on a classic n-tier project once many moons ago and they insisted on creating a version of the data objects for each level of the system. The API had their viewmodels, the business layer had business objects and the data layer had the EF data models. AutoMapper was plumbed in at every level to convert the data objects back and forth as data flowed up and down the layers! It was crazy and so annoying!
Imagine calling a getuser api, that calls a getuser() function on a business layer user service that called a getuser() function on a repository. The repository the wrapped around EF would return a DB User object to the user service, that automapper would convert to a BL User object to return to the controller that would then user automapper to convert to a ViewModel User object to be returned to the frontend!
I have recently joined a project where they are doing just that!
My understanding is that mappers that map at runtime do it using reflection. When large numbers of records are concerned, that is a massive performance hit. You wouldn't use it in high performance scenarios.
The fact that people are doing too much with it doesnt mean it doesnt serve its purpose.. it's awesome in generic code for many reasons.. now i could write my own simple generic automapper that does the same... but i dont see the point.. it's good enough and simple enough for my need.. it need way less maintenance than manual mapping..
Manual mapping, though not with extension methods, as those may pollute IntelliSense suggestions too much - I simply use a static class as a "namespace" for mapping methods
I forbade my team from introducing AutoMapper in projects I inherited, and I'm vocal about it whenever I encounter it in other projects. However, I realize that my experience (a decade ago) is simply not transferable. I presented several reasons not to use AutoMapper, but no one ever listened. I'm happy to see you spreading this "idea"; hopefully, more people will listen to you. 😊
Hey, just use: public static SomeDto ToDto(this SomeDomain) so nothing gets polluted. The extension will only be shown on "SomeDomain".
Apart from all the issues mentioned… No one needs all that extra maintenance of maintaining a third party dependency that proliferated throughout your entire codebase. We have the simple mantra: “Minimise 3rd party dependencies“.
As I also pointed out in the post on Reddit, there are deeper problems in your architecture if you're reaching out for a mapping solution. Extension methods for sure are the way to go if you absolutely need to, but you should also re-consider what you're doing with your classes if you're finding a 1-1 relationship with many of your properties. Your contracts/DTO/queries/whatever you want to call them just might be very bloated and unclear in their purpose. It's an apt time to rethink why this yak-shaving step is so necessary in your architecture.
It's the same problem with microservice vs. monoliths. The problem is the intentionality of your code, not the logistics of moving data around. Leave that for performance optimization.
Sometimes it is not a problem with the architecture per se, but with the external tooling. It is not an easy feat to do very strict and behavior modeled C# objects play well with ORMs for example (which in turn leads you into needing the separation between your business models and your data storing entities) or even to respond to common user requests that requires only a very small subset of properties from a larger query (which is common in many more complex products). There are times you can hardly avoid mapping solutions, and I don't think your generalistic advise is a good thing.
I interested to see Nick cover EF projection into a dto class? Do you build something to assist with those projection mappings?
EF projection is the only thing I use AutoMapper for. Maybe this is the best use for AutoMapper? I have no problems and my code feels clean and organized.
He talks about not using Mapper for anything else and not to include logic in it, but I don't quite know what he's using if it's not a mapper?
He said he builds extensions methods at 3:07 like MapToDto..? I guess that would work but Mapper and EF just work so well together why bother.
AutoMapper helps a lot to catch mapping errors.
Imagine you have an entity and DTO. At some point in time, you need to add one new property or two. You add them to DTO and entity, but forget to modify the mapping method. You end up with a bug report from the customer.
Here is what we do:
We write a single unit test, which creates an instance of IMapper followed by adding all mapping profiles using assembly scan. Then we call AssertConfigurationIsValid. Test will fail if you have unmapped or incorrectly mapped properties.
With CI configured to run unit tests, you get your application mapping tested early.
4:02 the passion displayed here is how i feel about these things aswell! Move as many things to compile time as you can, therefore use mapperly a source generation mapper, use strict mapping to ensure you never miss a mapping again (this is a benefit over manual mapping) and turn those warnings into errors with your .editorconfig or the likes.
Always write your own mappers. If they use a mapping library internally, then that's an implementation detail and the rest of your code should not be aware of it. If you have a "special case", then skip the library and write that one manually, but the consuming code should be none the wiser. The advantage of using a mapping library IN your mappers is that when someone adds a new property, you don't have to rely on an easily distracted human to remember to add it to the mapper by hand. You get to code just the exceptions.
Exactly. This is what I did 15 years ago. People learn slowly. Automapoer was always bad for 99% of projects
And do you know what is another library that is also too often used and from same author? 😀
@@PeriMCS I've been burned by the easily distracted human leaving off the new property more often than I have by AutoMapper being cumbersome. I'm all about the Mapperly now. Compile-time checking and automatic inclusion of new properties as long as they're simple. It gets me 90% of the way there, and I can handle the remaining 10%. I'm still going to hide it inside a concrete mapper class, though, so I can fully take over any time I find a weird case.
@@PeriMCS Something to do with 8r ? In some environments where I have worked, they worship that library but it is a pain in the *arse because intellisense, 'Goto Definition' and 'Goto Implementation' can't handle it. Likewise, if you want to debug a command handler, you have to know which handler to debug and place a break point in it because debugging doesn't step into the handler code.
9:05 Yep, it's like the slippery slope of OO hell I always see in Java projects with ObserverIteratorFactoryMapperClientProducerContext type abstractions. Working on a large project for years all of those clever things you come up with you will literally forget then you have to relearn everything you did. Keep it as simple as possible always and it will usually be the best solution in the long run.
love all the advice here: prefer compile-time errors over runtime error, keep related code together, and KISS.
We started migrarion to Mapperly this year. The more we do it - the more people like it.
Until you'll find out Expressions are not supported, so support for projections with EF is incomplete.
@@tedchirvasiu
Expressions are supported, it is in the docs. But I also think that you can circumvent that temporary limitation without much hassle anyways.
In our current project, we try to avoid external libraries the best we can. Because every library needs a certain amount of attention (MEND warnings because of vulnerabilities etc) and produces maintenance costs. Hand-written or Copilot generated mapping methods are easier to debug, easier to read, faster. Just fire-and-forget.
I like a simple IMapping interface that has a TTo Map(TFrom), and that's it. I can DI, reuse it, I might have some frequently used enums that I want to translate between, and its just doing the one complex thing. If its super-simple, extension method, static mappers and whatnot is fine, but now and then it might be a little more complicated than flat entity to flat DTO and reverse. If you ever have the misfortune of working with UBLs, you will not be happy with anything
If you use automapper as intended and only as a mapping tool, then it does saves heaps, though it did make me do a double take where object hierary was mapped uaing conventional name based mapping
Recently have started using source generator mapperly
Challenge accepted. "Fixed" my code and removed Automapper. It wasn't difficult using extension methods. But honestly, not seeing a savings in terms of maintenance. Agree that runtime errors avoided will be worth it. I think there is room for Automapper in the prototyping phase, or early stage, of a project. It's a well written useful tool and I'll still use it when it makes sense.
Thanks for this video, I have been arguing against mappers for 10 years for these reasons and because it also hides the dependency between classes, especially in lazy usages where you do not setup the mapping in advance but use it adhoc.
Having this video to point to will be helpful :)
Yes there are some cases where a mapper is useful and do not add problems, like mapping from a DB where you just name the properties the same as the field (even if today I would mostly use dapper or some similar ORM solution, but thats still a mapper), since in that case there are no compile time connection between the sql query and the class anyway. You can use Entity framework for that and get a compile time mapping but that is not always the best solution for more extreme databases.
And the extension method is also my goto solution in most cases except when I have many sub projects and there is a risk that you just did not include the right namespace. In those cases I have used a static method on the actual data class, I know this looks bad, but it ensures that the conversion method can be discovered by a developer unfamiliar with the code base.
I prefer the extension solution since it keeps all such logic separate and as long as you have a common "conversion" namespace it should not be a problem.
Anytime you need logic, then its not a mapper and you should use a factory, transformer or some other solution that explicitly indicates that its not just a mapping but something more.
Having something look like a simple mapper that under the hood makes an sql query to add more data and then have another unsuspecting developer use the "mapper" on the 100 000 row result set, tanking the server, is not the best way to learn why its bad (might be the most efficient learning way, but with a high cost)
I love Mapperly. It saves me time while still allowing me to expose errors at compile time.
Real question: if you have manual mapping, how do you handle mapping expressions over the mapped entities?
Specifically, if the backend is Entity Framework, you cannot simply couple the expression with a projection to the mapped types and still get a reasonable compiled SQL query.
Shouldn't a mapper just 'map' ? If it is performing any kind of expression evaluation or conversion, then it isn't 'mapping'. And if Entity Framework is doing projections, isn't that a form of mapping - why are you double mapping with AutoMapper ?
@gppsoftware I am not double mapping.
I have an endpoint that exposes data using the OData protocol. That means calls to the endpoint yield an IQueryable of TContract, meaning an expression. If the mapping from TContract to and from TData is done manually, how do you propose converting IQueryable of TContract to IQueryable of TData? I've tried writing an expression conversion visitor, but that's REALLY manual and cannot leverage the manual mapping well. We've used AutoMapper for this, and it works... ok-ish. It does the job mostly but has a lot of cases it does not support.
@@jamesterwilliger3176 Easy. `IQueryable ProjectToB(this IQueryable q) => q.Select(i => new B { One = i.One, Two = i.Related.Two, Three = i.Related.OneMoreRelated.Three });`
I never really understood what mappers are good for. Until I was working on a project where automapper was used and it was helpful. Maybe we were lucky to only use it for simple mapping (and a few easily understandable complex ones, but 99% were simple and the fact that it worked out of box was helpful). I'm not sure whether I would choose any mapper library for a new project, but I can see the value when used correctly.
I LOL’ed with the “password encrypted in the mapper…Jesus Christ, what the hell!?”
Well-said and thank you Nick. I 100% agree with this. I’d rather struggle with the less complexity of manual mapping of even a large class rather than chase down the invisible runtime issues and scattered mapping logic that ensues when using automapping libraries / services.
Good video! I use manual mapping as well. However, the only thing that makes me use AutoMapper still is mapping expressions using the AutoMapper.Expression library. Because expression mapping, oh my god is difficult.
4:07
You can also easily make a general extension method and use an interface with for example an abstract static method to generalize your mappes, so you can do things like:
query.MapTo()
and
list.MapTo()
with ease and without needing to create many extension methods in your projects.
THANK you! You're the first dev I've seen in a while who seems to get how markedly beneficial extensions can be!
Using reflection?
@@z0nx
Nop, you just need some generic constraints and it is all good.
I think this website don't like when I paste code as it hides my comments, so it is hard to give an example, but look into "generics" (for the basic construct on the language), then "static abstract interface members" (for having access to static properties and methods of types) and normal "generic constraints" for specifying which interfaces your types need to implement in order for a method to be callable. Then look into the concept of "extension methods" and you can just mix those and make a good, fast and reliable extension method that will enable you to make your code more concise.
@@NickTheCodeMechanic
I think people have a hard time putting together many of the C# concepts (like generics, constraints, static members on interfaces, extensions and all) to come up with interesting ideas, but if this I said can help someone I'm already happy.
I'm also looking forward to the new extensions feature of C# (if/when they release it) as it will (I hope so much) solve one of the biggest painpoints of extensions right now (which is, you cannot have partial type inference in C#, so if you want to have the first generic argument be inferred and the others be explicit you are out of luck).
@@diadetediotedio6918 I know all those concepts, I just wonder why you would use this for mapping. Why use an interface? So you can have multiple implementations? We are talking about mapping right? The same kind of code that nick mentioned that should be as simple as possible.
6:55
Mapperly also allows for easy escape hatches from the library, which kinda solves the problem for the 80% of the cases but let's you do the 20% a bit more complex. This is already a good balance instead of needing to do it all manually.
I stopped using AutoMapper about two years ago. At first, I wrote everything manually, but after I came across Mapperly, I use it for simple mappings. If the mapping is really complex, which I try not to allow in my code, then I write the mapping by hand, since in this case more control over the mapping process is needed.
Write it by hand and use a .Map(this T obj, func mapper).
Extension method, so you can easily chain your mapping...
Don't forget to return T after performing the Func...
I think, I've found the best scenario (for me at least). Mapperly-generated extensions + custom extensions. All simple enough logic is done by Mapperly. Moreover, Mapperly can raise compile-time errors (warnings actually, but you can treat them as errors) and help you to avoid many mistakes. And if Maperly itself is not enough - you are free to create extra extensions. You can even combine Mapperly-generated and custom logic. That is so convenient!
Are you using Vogen in your domain? I spotted From in the construction
Same here - got rid of all automapping and moved to manual since it made a lot more sense and also much more simple for our juniors to understand. While the idea is cool it complicates everything to a point where when running massive apps with a lot of edge cases it becomes an absolute nightmare to deal with! No automapping EOD 👀🙈💗
We use AutoMapper - More problems than benefits.
EF is the same way. One of the companies I left used it and kept writing all sorts of 'filters' for the main dashboards table everywhere in the codebase. It was 8 year old code and 8 layers of spaghetti hell.
All to filter a bloody table.
Datalogic. That was the parent company....
I wanted so bad to simplify the code, but there was no documentation to speak of and their Sr dev quit for that reason, and the lack of solid direction in the project.
Hairiest code base I ever saw in my life.
The SQL 'config logic' was a like 5 separate sql files, each thousands of loc long filled with insert into over and over. No json or anything... no,we can't have that!
And 5 different tables I think, just to update a simple key value pair (i forget what for) in the db (oh wait, right, it was undocumented, so I never knew whag it was for! My bad)....
I was fired after trying for a week to figure the code out. 3 weeks prior, the laptop ate itself alive thanks to windows 11.
Idk why, but soooo many "Microsoft shops" are full of this kind of incompetence.
Idk how it's so hard to run sql and turn it into HTML. Really, is it so hard?
😠 😡 👿 😤
Automapper is cool with GraphQL (HotChocolate) though, because it maps projections. Select fields from an API model, map to entity, your query is rewritten correctly into SQL, map back
I would prefer to write "smart" tests (like using reflection to check if all properties are present on both sides) and keep the mapping function simple. Compiler helps, but it is not enough to enforce design and contracts.
Hello, just wondering how would you resolve our case. We use custom datetime converter inside mapper, and in your approach we will need to pass a converter inside extension method or add one more layer to do this time convert
I only used AutoMapper in one of my projects. Enough to know I will never use it again and it's still a pain in the ass to maintain. I actually do the same thing Nick talks about, an extension method. Super simple and intuitive, also extremely easy to maintain.
i agree with most comments, but you said writing custom mapping is fine..
what would you do when you have to map 100s of fields? or maybe map a master and detail data where each has 100s of fields? that's defintely not a 2 minutes job.
Now I remember, I was on a project with a LOB app, WPF, and they have had consultants working on project basis on this. So many different styles of coding based on the developers understanding of MVVM. A lot of legacy code. But the AutoMapper configurations were set inline in views - that were hard to locate. And that made it harder to see how it mapped object. So the down-side, if we ignore reflection, is debuggability, especially when the mappings are not obvious. I very much prefer to write my own manual mappings nowadays.
When I am going trough code that uses automapper, i always find it confusing how objects are being translated while manual mapping makes it clear and very simple. So I always try to steer away from it. I even had this discussion yesterday with colleagues, so I will be using this video :)
Pro Tip: Write your manual mapping code as expressions! Expression Map(...)
Then you can use them to project results from database into your DTO or whatever result object already on DB layer. This way you will avoid bringing unnecessary information from DB into program's memory, therefore solving the "over selecting" problem. ;)
(If you insist using mappers, AutoMapper, Mapster, Mapperly, whatever, then those can also produce expression mapping... If you insist.)
I really like this idea! It can decouple the mapping code from the type, allowing you to specify mappers with far more flexibility and explicitly, improving visibility also.
Never managed to get that working. I have dto projections inside dto projections and apparently c# can't deal with that
@@HaeriStudios nested models have always worked for me through expressions and in linq.
@@GigAHerZ64 I've been chatting with multiple generations of ChatGPT and Claude to figure this out to no avail. How do you call the function in the nested mapping?
I write my automapper code as expressions. This tip isnt really tied to mapping, though. Fetching code using an expression is recommended instead of fetching all the fields and then picking what you want.
Negative value of mappers is quite clear. But if we consider Mediatr, don't you think it's overhyped and does not bring real benefits for Web API projects? (Unless you really need and actively use mediator design pattern for something)
I prefer manual mapping for control. And I often add a property that needs business logic and with manual mapping it's easy to customize. And mapping is something we just do once and seldom change, so not much time to save imho.
Where is the link in the description. I guess you forgot about it. 🙂
We use AutoMapper in a niche of our modular monolith.
We have one legacy application that forces pretty dumb models upon us in a SOAP API and we remodel it into something useful and expose it in a REST API.
Thats where Automapper is pretty strong, its simple mappings, barely to no logic at all and it saves us a bit of time writing our own mapping code.
Other than that I agree, I wouldnt use a library when you can just write your own static extension to map into something else. Just makes debugging things a lot easier
I've never found mapping to be a good enough reason to add another project dependency.
Which, if you think about it, is another project in itself....one you don't control and have to obey a specific paradigm in order to squeeze out a tiny drop of benefit from...
@@NickTheCodeMechanic We do almost everything by hand insted of using libraries. Too many times have we been smacked on the butt because something is deprecated and we had to rewrite it from scratch anyway. We use nugets from microsoft (which can of course also be deprecated) and some inhouse nugets that we have control over but thats it.
In my personal projects i like to try different nugets for fun, but it does not feel reliable to use them in a work setting with real production code
Thank God there‘s developers out there that understand this. Are you in the market for new gigs?
@@fredrikjosefsson3373We also work from the principle “Minimise dependencies“. One of the best decisions we‘ve ever made.
Code generation is a good middle ground. Now your exceptional cases are at generation time, thankfully most libraries that do this kind of thing tend to have good stack traces and docs.
There was a moment when the best mapping solution was a code generation plugin to visual - or generated mapping template, you could change it to whatever you want
Now in fact it was superseded by the copilot
How do I hide Entity properties, how do I customize responses based on profiles/roles, how do then translate filters to SQL ?
If I am working on Clean Architecture project, Should I only put the DTOs in domain layer?
What if I have variations of CustomerDTO like CustomerDTO to RabbitMQ, CustomerDTO for REST API, etc?
I'm currently using Mapperly that creates mappings using Source Generators, its awesome
AutoMapper is a pain in the rear. I've never once voluntarily worked with it, but unfortunately I have certainly come into contact with it plenty.
Code bases where they probably started with 'map from [prefx_FieldName] to [FieldName]' or something. Easy enough right, mapper it is.
The problem is that those people that use it generally end up with totally convoluted profiles due to it never quite turning out that simple.
After all, sometimes we end up with fields that don't match in name, fields to ignore, custom stuff for certain fields, dual direction mapping, etc.
I've ended up in projects where the AutoMapping was really some giant black box, using multiple profiles, mapping in multiple directions, and you had no friggin clue what the heck was going on anymore with all that profile shizzle. And since you don't actually have code to set a breakpoint, you're kinda up the creek without a paddle.
WORSE YET, the 'upgrade experience' on that library has been a total nightmare over the years.
I get it, the DEV wants to optimize and improve as time goes on. But upgrading those stupidly complex implementations pretty much amounted to a full rework, trying to figure out how to get it rewritten in the new version due to a ton of breaking changes.
What could make sense would be an extension for Visual Studio, which the user would pick two classes in the Solution Explorer, and then open an Wizard "Generate Mapping".
It's called copilot 😊
Look for "MappingGenerator" extension. It's not perfect, but saves some time when doing manual mapping)
I belive it depends on the project.
But you should definitely add the unit test that checks at compile time the mappings
I used to write my own mappings because I did not know about the existence of mappers. Then I found out about them and asked myself: "Well isn't this overcomplicating things? Isn't this trying to generalize something not really generalizable? Why does this even exist?". Well, well, well ...
"It pays dividends to be simpler". Well said!
I've never been a fan Mappers and never used them, some devs swear by them, I don't like them. Like most I use manually mapping :)
I've been using automapper since it came out and never liked it! The main reason I see to use it is because it often seems to be the least painful solution at the time... emphasis on the word "seems", there are definitely projects that I have worked on where automapper was a major source pain! I guess I could give an advice like keep you implementation of automapper simple but that defeats some of purpose of having a fully feature software tool... There is always manual mapping... but that's the initial pain I'm trying to get rid of :(
It’s a trade off like everything else. I think AM made sense as a feedback loop for unmapped fields in older versions of .net but with init/required keywords there is now a built in feedback loop with manual mapping code. Adding those keywords is want made AM no longer a good trade off
I use Mapster. It's initialized as a part of a static class which contains it's instance. When doing "regular" mapping, invoke mapster. When I need something special, I add a static method. Problem solved, best of both worlds.
I totally agree!
I don't hate AM, I just realized, if you need to map something, there should be compilation-time mapping generation, later, I realized that I don't need mapping at all.
So, I completely stopped using it in my old XF-based application for new features in the project. My primary concern was a performance one.
The biggest mistake is to stubbornly stick to one method and complaining about drills being unable to screw the nails in. Use damn the hammer if it's suitable.
Just do thin wrapper and treat auto mapping as implementation detail. You can switch to suitable method there, auto or manual becomes a mere detail.
Thank you for your efforts.
Is there an easy way also to replace automapper .ProjectTo functionality used with Efcore
I looked at it once, but it was not long before I realize I could make a much more performative version to suit my needs.
I love it when Nick gets flustered about bad unit test practices.
But how to find all extension methods, if your domain class will be extended with a new property? Quite often this new property you need to map to all responses and DTOs
I stopped using AutoMapper a few years ago, best choice ever. Runtime errors instead of compilation errors, poor performance, a lot of magic sometimes. Just map it manually, it’s not hard, we have tools to help with that, it will be easier to maintain and reason about and it’s one less dependency to worry about.
Por que no los dos? Use mapperly for trival 1:1 maps, and write extension methods w/ manually mapping for anything non-trivial
Another ding against automapper is the amount of memory it uses. The guys who first wrote the app I currently work on, I swear automapper paid them a nickle for every time they called the method. Most models go through 3 mappings in our "backend' project (sometimes more, occasionally less), and most of that goes through our "BFF" with 2 more mappings, before going to the client. Automapper profiles take up a couple hundred MB of RAM.
I mostly just use a generic method that maps properties with same name and type automatically with reflection. I also have two custom attributes I use to annotate properties where names differ, either MapTo or MapFrom. It's like 30 lines of code. Works just fine for me. Don't need anything more complicated.
Reflection will give a massive performance hit on large numbers of records. Direct coding is far faster.
@@gppsoftware Sure, but performance isn't all there is, and isn't always that important... I wouldn't use this to map an entire collection.
AutoMapper should be kept simple. It is great for domain to dto mapping with no, to minor conversions/translations (Class to class mappings). Mocking auto mapper is also going to miss issues.
Ditched it years ago. It‘s a shitty concept in practice, just like ORMs. Just generate the code explicitly.
I use implicit mapping to convert between domain entities and request models, ef core expression mapping to convert from domain entities to DTOs, ever since never used mapping libraries.
I disagree with the position that a mapper cannot have dependencies.
In some projects where the SPA frontend needs to display the current user permissions, the easiest way is to inject the AuthorizationService and return to the user what he can do with the current entity.
The moment you do something a little bit complex in a mapper, you are doing it wrong.
The only place where I think they have a large benefit, is when there is added a field/property on either the from or the to, and a UnitTest or startup Validation can pick up a missing mapping. If I could get an analyzer that picket this up, I would not see any benefit with mappers today.
I do like Mapperly the most, but I did have an issue with one version when using Rider (but not in Visual Studio). But at least with Mapperly it's easy to migrate away from it.
I actually like this take, i've used Mapster a lot and though it really makes a lot of stuff super easy, it has also sometimes been a huge pain when stuff i not working as expected and it does sometime make it feel very "magical".
How would you go about Many to One mapping?
Tuple? Parameters on your mapping extension?
This screams more of a change in fad than actual practical advise to make things better. I've used AutoMapper in quite a few projects and it has worked wonderfully. I prefer the IMapper interface to spreading extension methods out all over the place. It does a lot of nice things we use.
Mapperly looks promising, I will check that out. Other than that, in my whole career I tried to avoid using Automapper as much as possible, due to the already-discussed topics here.
In my project we use Automapper, but we try to not hide logic in the mapping. We have a lot of entities mapped to Dtos that are almost exactly the same so it helps a lot.
The thing with manual mapping is that, if the mappings are not centralized in a single place, you may forget to update a random mapping when you add a new property to your entities, and when you centralize the extension methods in a single file, it becomes a bit messy (MapToDto, MapToCreateDto, MapFromDto, MapFromCreateDto, etc.).
The bad part is that you only know that you missed a mapping after testing it.
Have you tried to make the property required? then the compiler should notify all places where you forgot to set it.
The only use-cases I can think of that play to automappers strengths are when mapping a graph or tree structure that can contain "random" node types
Mapperly is "better" in the sense that the mapping errors are exposed at compile-time instead of run-time. But the generated code is still out of sight, out of mind. Omissions in mapped fields won't be obvious at all until you run the code and data just isn't present. I just don't really understand the need to generate mapping code in the first place: Mapping code tends to be easy to write, easy to test, and gives you complete flexibility to evolve models in different layers independently without having to worry about whether the mapping library can figure out how to map one to the other.
with the introduction of chat-gpt there is absolutely no point in using automapper. complex cases were a pain to manage to begin with, introducing errors that took hours to find. It was mostly used to not waste time mapping classes to dto's 1 to 1. Now, you can just make chat-gpt, copilot, cursor generate the mapping code for the simple cases and handle the complex ones in your own code-base, making it easier to maintain.
Jimmy might be upset. But wonderful video. Long needed. Why did nobody say this before. Like the emperors clothes. I do not love extension methods, for similar reasons. Mapperly sounds like a win.
I am using automapper, very little custom code added.
And it is working just fine, it does the job... however i would like to have one where i can see more clear the properties mapped, and what happens on a rename.
I was totally against automatic mappers till I ended up having to fix tons of DTO mapping issues by devs who copy-pasted manual mapping incorrectly leading to incredibly hard-to-find bugs because they didn't add proper testing. And even in cases where they did add tests, they simply copy-pasted bad property mapping into the tests themselves which was even worse. At that point I realised the value of automatic mapping libraries. Since I've started using them I've experienced far, far fewer issues related to mapping then before. However, unlike this video I'm certainly not dogmatic about it. Mapping libraries are tools just like any other. It's all about understanding their use-cases, utilising their strengths and mitigating against weaknesses.
Maybe use some kind of code review to not let that bad code into your codebase ;)
Debugging when using automapper is a pain and not always useful... I agree with creating your own mapping.
I once worked on a project where the auto mapper configurations had a lot of ignores defined and I thought how stupid is that I am reading what we don’t want to map instead of reading what we want to map.
I've worked at several places where mappers are used and I don't like them. OK sure you are mapping a DTO to or from some domain object and it seems perfectly nice to think that passing the two through mapping will give quick results. My issue is that you cannot be sure what will happen if a new property is added or if for some reason you want to rename a mapped property. If the code is written by hand then you might find you miss a property but good unit testing should reveal this and I'd also say that when I've done this lately, tools like Visual Studio seem to understand what you are doing and propose to complete it line by line and I'm sure AI or a dedicated mapping code builder will take that even further.
What you mean? We know exactly what will happen, the info will not be populated if the properties dont match. If they match but are of different types, it will throw an error.
@shadowkras It depends on what rules are set for the auto mapper. If you are unfortunate your unit tests may pass but then some user enters a valid value that doesn't map.
@@NickAskew What you describe sounds like the job of a validation class/method.
@@shadowkras Absolutely but would you create that validation by hand? If not then we are simply back to square one because the code that generates it can still be wrongly configured.
I really do think there is scope for a type of automapper but for me it might be part of the development environment prompting the developer when changes are made to the mapped objects.
Suppose I add a new field to the application layer object called perhaps UserIdentifier and this should map to UserID. We can detect these changes and be prompted to link them. These could be visual in the development environment or output as warnings or errors for the developer to review. Then the validator can also be updated to ensure correct behaviour.
@@NickAskew What you mean create validation by hand? Is there any other way to create validation?
You need to tell the code to validate a property and how it should be validated. There are dozens of ways and tools to do it, but you still have to do it "by hand".
Recently, I found out the hard way that Mapster had different behaviors when mapping/merging records vs class objects.
myViewModel.Map(MyDto obj);
myDto.Map(MyViewModel obj);
That's what I end up with a lot of times and do manual mapping inside. And yeah, AI auto generating makes things super fast.
If you can't use AI, then use Mapperly if it's simple, do it manually if it's complex.
my problem with automapper is absence of async and after version 11.0.1 there was one breaking change that i rly dislike:
classA a = null;
classB b = new();
mapper.Map(a, b);
11.0.1 b is null
after that b is unchanged
also automapping is fine until somebody else wants to change something in your code and trying to find where is some property used, even though that property is mapped to another with same name in different class, you will not find it by "Find all references"
This is why i am going to try mapperly next time i want to use mapping (source generated mapping) in my mind it should bring best from both worlds, i do not have to type simple mapping every time i add properties but also should give me opportunity to use async and Find all references will work, this way i don't see need to completely stop using any kind of mapper
Why would you need async mapping?
@@EikeSchwass in our microservice architecture, we have microservice for enums and their transformation to enums of other external vendors
We miss trade-off here. When project is evolving we make more issues with manually mapping, from forgetting to map to mapping straight incorrectly. I’ve seen bugs in production like that. Code generators are better solution.