Skip to content
JulianR edited this page Aug 21, 2011 · 36 revisions

Overview

Pages

ThisMember

ThisMember is a library to make mapping of members on types that have something in common, easy and fast. Its aims are:

  • Convention over configuration. If you don't specify something, ThisMember will make a best effort attempt.
  • But if you do want or need to configure something, ThisMember should give you the possibility to.
  • It should be fast. It's allowed some warm-up time, but after that every mapping call should ideally be not significantly different from creating your mappings manually.
  • Easy API. Every operation should have a generic, strongly typed variant, as well as a reflection based one.

Essentially, it should try to let you have your cake and let you eat most of it too.

Simplest example

var mapper = new MemberMapper();

var result = mapper.Map<SourceType, DestinationType>(source);

Example with a custom mapping

var mapper = new MemberMapper();

mapper.CreateMap<Customer, CustomerDto>(source => new CustomerDto
{
  FullName = source.FirstName + " " + source.LastName,
  TotalOrderAmount = source.Orders.Sum(o => o.Amount)
});

Use cases

Productivity

There are a lot of scenarios in which mapping of one type, to another similar type is needed. You may receive a view model or a data-transfer-object (DTO) of for example a user, that you wish to update and store in the database. But your data layer of course uses a data model and you would need to make the translation, or mapping, of the view model to this data model yourself, through tedious lines of assigning properties even though most properties are exactly the same on both sides. Or perhaps it happens the other way around: you have a data model that you retrieved from a database and wish to turn this into a view model.

ThisMember allows you to easily do that, it's capable of generating mappings between two types on its own, while allowing you to specify your own customizations to them as well.

Verifiability

By default ThisMember is very permissive and won't complain if there's a member on the destination type which does not have a corresponding mapping from the source type. And in a lot of cases, you may not care about that or want to be bothered with meaningless exceptions of non-matching members. However, it often to makes sense to verify that you didn't forget to set a property, which you can't do when you make your mappings manually, other than by writing a lot of code to verify this, which in turn also needs to be maintained (which you can also forget).

With ThisMember, you can opt in to be warned if a destination member is not being mapped properly. Maybe you added a column to your database and a property to your data model recently, but forget to add it to the view model. Perhaps you did add it to the view model, but forgot to actually set the property somewhere. Or maybe you actually don't want the property to be there on your view model, ThisMember will force you to be explicit about your intentions.

In all those cases, if you turned on the option, ThisMember will throw an exception.

You won't have to wait until your application is running in a production environment though, you can just write a unit test that verifies the mappings that you care about to be correct.

Utility

ThisMember allows you to easily make a deep clone of any object.

Change History

1.0.0

Bumped the version number to 1.0.0 to indicate that I consider it a stable library, meaning that I will try to limit breaking changes to it.

  • Added the ability to pass in parameters of any type to be used in a custom mapping, as part of the mapping process.
  • Improved thread safety.
  • Improved cloning: prevented maps of reasonably complex types with many navigation properties to become ridiculously large (10k+ LoC) by adding a configurable maximum recursion depth to deep cloning (mapper.Options.Conventions.MaxCloneDepth).
  • Fixed a bug with recursion where a property being skipped on a type because of a recursive relationship, would cause it to be skipped in a different situation as well where there was no danger of infinite recursion.

0.8.5

  • Fixed bug where a constructor was expected on value types like decimal when mapping from a source object to a destination object of the same type.

0.8.3

  • Added Page method to ICollectionProjectable, for paged results.

0.8.2

  • Fixed a bug where AsCollectionProjectable returned IOptionalProjectable<T>.

0.8.1

  • Added CreateProjection methods to IMemberMapper.
  • Fixed bug where an exception occurred during map-creation because two incompatible types were being assigned to each other.

0.8.0

  • Added first version of Project API to IMemberMapper. This returns a mapping as an expression, for use as the projections in for example LINQ-to-Entity queries (so for example query.Select(mapper.Project<Source,Destination>())). Supported right now are simple member-to-member mappings (including collections) and most custom mappings.
  • Added several varying IProjectable interfaces, that allow you to specify a projection on the result of a sequence (can be anything from an array to a database query) without allowing you to alter the sequence. Useful for bridging some awkwardness between a data access layer and a service layer.

0.7.6

  • Fixed a bug where making a deep clone of an object did in fact not.
  • Fixed a NullReferenceException that happened when you explicitly passed in a null destination object.
  • Fixed a bug where members of type ICollection<T> would cause an exception during the mapping procress.

Next Version

  • Parameters in your maps that can be used in your custom mappings.
  • ThisMember will not only be able to map in-memory objects, but will be able to provide an expression that can be used in Linq-to-SQL and Linq-to-Entity queries as your projections, allowing you to use your mappings in your queries. Implemented in 0.8.0
  • ThisMember will provide an IProjectable<T> interface, allowing you to do query projections inside the service layer of your application, but the actual queries inside the data access layer. Implemented in 0.8.0

Future Versions

  • More advanced conventions, like automatically flattening object hierarchies during mapping (so: mapping source.Address.Street to destination.AddressStreet.
  • More advanced custom mappings, allowing custom mappings of arbitrary depth rather than just the flat custom mappings.
  • Safe mapping of recursive relationships
Clone this wiki locally