Use LINQ’s Select and Initializers to Make Mapping Easier

16 February 2010 | Scott Williams | .NET 3.5, C#, LINQ

Mapping data between types on a Web Service can be a collosal pain. There are various frameworks out there that can speed things up, but sometimes you just need to do it by hand. Fortunately some of the features introduced with C# 3 can help speed things up.

Say the type on the server looks like this:

class ServerType {
    public int ProductId { get; set; }
}

And your client type looks like:

class ClientType {
    public int Id { get; set; }
}

[This is a gross simplification, typically the types have more differences, but it gets the point across.]

Let’s say that the web service takes a List<ServerType> as one of its parameters too. Typically before C# you would need to do something like this:

public List ConvertClientList(List<ClientType> clientTypes) {
    List serverTypes = new List<ServerType>();
    foreach (ClientType clientType in clientTypes) {
        ServerType serverType = new ServerType();
        serverType.ProductId = clientType.Id;
        serverTypes.Add(serverType);
    }
    return serverTypes;
}

Ugh. That is far too much code and typing. Fortunately we can drop that to a one-liner with LINQ and Class Initializers:

var serverTypes =
    clientTypes.Select(c => new ServerType { ProductId = c.Id }).ToList();

Bingo. Let’s walk through this a little bit just to be clear. On every item in the clientTypes List, the Select function is being called. It is instantiating a new ServerType object and setting the ProductId property. The default payload of the function in select is to return the expression, hence the lack of a ‘return’ statement; it is implied. Select returns an IQueryable by default to allow more chaining of expressions. Here we don’t need to do that, so we convert the whole thing back to a List.

The Select function is very powerful. It let’s you transform a collection of objects of one type to something else entirely. The result doesn’t even have to be a known type! For further magic on Select, read this article.

5 Responses to “Use LINQ’s Select and Initializers to Make Mapping Easier”

  • 1 Devin Allen Says:

    This is great stuff. I’ve been using a lot of LINQ features with MVC and it make so many things such a breeze.

  • 2 Michael Melendez Says:

    For data conversions you can also use the predicate functions that were added in 2.0. But I still prefer your Linq method ;)

    var serverTypes =
    clientTypes.ConvertAll(delegate(ClientType c) { return new ServerType{ ProductId = c.Id });

  • 3 Scott Williams Says:

    Thanks Mike, but I’m pretty sure Initializers weren’t added until C# 3 :-). “return new ServerType{ ProductId = c.Id }”

  • 4 Eric Swanson Says:

    Couldn’t agree more. I like to wrap the mapping in a class; something like “IBusinessEntityTransformer” that has two methods “TEntity ToEntity(TContract contract)” and “TContract ToContract(TEntity entity)”.

    With this, your implementation would look something like…

    public class ClientServerTypeTransformer : IBusinessEntityTransformer
    {
    public ClientType ToContract(ServerType entity)
    {
    return new ClientType()
    {
    Id = entity.ProductId
    };
    }

    public ServerType ToEntity(ClientType contract)
    {
    return new ServerType()
    {
    ProductId = entity.Id
    };
    }
    }

    Then, the LINQ statement becomes:

    var converter = new ClientServerTypeTransformer();
    var serverTypes = clientTypes.Select(contract => converter.ToEntity(contract));
    // .ToList() is optional

    *Seems like overkill for a 1-property class mapping, but I don’t think I’ve ever had a 1-property class for these types of transforms.

    **It’s interesting to note that the VS2008 Samples from Microsoft had an implementation of this mapper class as “static” and called it “Translator”. I can agree with “static”, but I disagree with their naming convention, since “Transform” is an industry naming convention for this type of mapping (see: Extract-Transform-Load “ETL” or eXtensible Stylesheet Language Transformations “XSLT”)

  • 5 Eric Swanson Says:

    Forgot to mention a major benefit: The transormation classes allow you to do deep-transformations (similar to deep cloning) for child object transforms.