Think Twice Before You Map Entities To DTOs

21 commentsWritten on September 1st, 2010 by
Categories: NHibernate, Performance

One thing that i see a lot, and that i have largely started to avoid, is that people fetch entities with NHibernate, only to transform them to DTO's so you can send them back to the client so they can be displayed in a a grid or some kind of list or whatever. This is usually pretty easy to do, especially if you already have a DTO mapper or are using something like Automapper. But this comes with a bit of overhead (both performance and memory) that you can often avoid quite easily.

Suppose i have a screen where i need to display entries based on the following DTO class:

    public class AuthorizationDto
    {
        public long Id { get; set; }
        public Guid ApplicationId { get; set; }
        public string ApplicationName { get; set; }
        public Guid? UserGroupId { get; set; }
        public string UserGroupName { get; set; }
        public Guid? UserId { get; set; }
        public string Username { get; set; }
        public Guid PermissionId { get; set; }
        public string PermissionName { get; set; }
        public string PermissionDescription { get; set; }
    }

This DTO basically contains data from 4 entities: Application, UserGroup, User and Permission. I could easily do something like this with NHibernate:

            var items = Session.CreateCriteria<Authorization>()
                .CreateAlias("Application", "a", JoinType.InnerJoin)
                .CreateAlias("User", "u", JoinType.LeftOuterJoin)
                .CreateAlias("UserGroup", "g", JoinType.LeftOuterJoin)
                .CreateAlias("Permission", "p", JoinType.InnerJoin)
                .Future<Authorization>();

            var dtos = new AuthorizationDtoMapper().ToDtos(items);

As you can see, that's very easy to do. Unfortunately, this code really does a lot of stuff that you might not realize. For starters, it retrieves all of the Authorization instances with its related Application, User, UserGroup and Permission instances. It also fetches those entities in their entirety, which means it's retrieving all of their properties while i only need their Id and Name properties really. And finally, NHibernate will set up all of the things that enable its magic for all of these entity instances. That takes a few more CPU cycles and uses more memory than you truly need for the scenario of fetching entities merely to return DTO's. This extra cost obviously becomes worse depending on the size of the resultset that you're fetching.

A better way to do this, is to simply let NHibernate fetch only the data (columns) that you need, and to let it populate the DTO's itself. You can easily do this using projections and the AliasToBeanResultTransformer class. The code would look like this:

            var dtos = Session.CreateCriteria<Authorization>()
                .CreateAlias("Application", "a", JoinType.InnerJoin)
                .CreateAlias("User", "u", JoinType.LeftOuterJoin)
                .CreateAlias("UserGroup", "g", JoinType.LeftOuterJoin)
                .CreateAlias("Permission", "p", JoinType.InnerJoin)
                .SetProjection(Projections.ProjectionList()
                    .Add(Projections.Id(), "Id")
                    .Add(Projections.Property("a.Id"), "ApplicationId")
                    .Add(Projections.Property("a.Name"), "ApplicationName")
                    .Add(Projections.Property("u.Id"), "UserId")
                    .Add(Projections.Property("u.UserName"), "Username")
                    .Add(Projections.Property("g.Id"), "UserGroupId")
                    .Add(Projections.Property("g.Name"), "UserGroupName")
                    .Add(Projections.Property("p.Id"), "PermissionId")
                    .Add(Projections.Property("p.Name"), "PermissionName")
                    .Add(Projections.Property("p.Description"), "PermissionDescription"))
                .SetResultTransformer(new AliasToBeanResultTransformer(typeof(AuthorizationDto)))
                .Future<AuthorizationDto>();

Granted, you need to write a bit more code. But that code will do far less than the first version.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    Why not just go the CQRS route, and have persistent view models? I’m not sure I’d ever want that many joins in a SQL statement that looks awfully important, and often used. I don’t think AutoMapper or projecting from entities is the problem here, it seems more fundamental to me. You’re still projecting, but just now at the SQL level. All those relationships still have to be navigated, this just pushes the problem down to SQL.

  • http://davybrion.com Davy Brion

    @Jimmy

    As interesting as CQRS is, not everybody can/will use it for every application. And the cost of those joins really isn’t that bad… if it is, i’d guess there’s something seriously wrong with your database or you’re getting tons of requests that the majority of applications that we all write never get in real life.

    But the joins aren’t really why i wrote this post. I just chose that example because it was right in front of me. The point is just that fetching entities (regardless of how many joins you need to do so) merely for the sake of returning their data through DTOs is (IMO) better done by projecting immediately into DTOs through your data layer, instead of going from entity to dto.

  • Morten Jacobsen

    Might I ask why you create the aliases in the first piece of code? Shouldn’t this be done automatically via the mapping?

  • Morten Jacobsen

    I was too quick to pull the trigger.. What I meant was, shouldn’t the joins happen automatically based on the mapping (of course the alias “a = Application” will not be done automatically)..

  • http://davybrion.com Davy Brion

    @Morten

    specifying the JoinType is optional, though i prefer to do that for clarity and it also allows you to override it (for instance, if you want to force an inner-join for an association that can be null)

    but if you don’t create the aliases, it won’t join the data by default, which would lead to numerous select n+1 problems (one for each association) that you’d use during the mapping to the DTO

  • http://twitter.com/vkornov Victor Kornov

    I’ve worked with NH pretty long ago, but should this be possible with new LINQ provider? I.e. replace all expicit projections with anonymous class e.g. :
    from a in Session.Linq()
    select new {
    ApplicationId = a.id,
    etc …
    }

  • http://davybrion.com Davy Brion

    @Victor

    good question, but i have no idea… i’ve never used the LINQ provider actually

  • http://sessionfactory.blogspot.com Diego Mijelshon

    Davy, if you really want to convince people, show the Linq and HQL versions, which are a lot cleaner (let me know if you’d like me to save you the trouble or writing them ;-) )

  • http://davybrion.com Davy Brion

    @Diego

    that would be great :p

  • David W Martines

    I use database Views, mapped directly to DTOs for my read-model (using NHibernate). This makes the queries very simple, since I’ve already denormalized and added aggregations/projections in the view. (I still use a properly normalized domain model for transactions, using a separate set of NH mapped entities). Naturally, I expose all of this to the client as Agatha requests :)

    • Simon

      You are basically describing CQRS, aside from the autonomous update components that keep the readonly views up-to-date. In general, how are you finding this architecture compared to traditional request/response on a heavyweight domain model, and what’s the performance and responsiveness like?

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #677

  • Daniel Fernandes

    Linq would indeed allow you to project to a DTO.
    The issue with the current Linq provider is that it’s very limited and should be used only in small scenarios, another reason why one shouldn’t put its eggs in one basket for querying, it’s best I found to directly depend on ISession and let queries do whatever is best, be it stored procedure called by NH, ICriteria, HQL or Linq.
    I see you’re using Future, I’ve never used it and never bothered to understand what it’s all about, maybe it’s about time.
    @daneel3001

  • http://davybrion.com Davy Brion
  • Adam

    Granted, you need to write a bit more code. But that code will do far less than the first version.

    I think if you consider the amount of code needed for AuthorizationDtoMapper, and that you can drop it after this change, you actually need less code.

    • Simon

      I thought the idea was to right LESS code that does MORE?

      Automapper can reduce your AuthorizationDtoMapper to about 2 lines.

      • http://davybrion.com Davy Brion

        as i mentioned in the beginning of the post, that causes memory and performance overhead which you can easily avoid

        writing less code that does more is a nice goal to have, but it can’t be the only thing you strive for

        • Simon

          Sorry Davy, I was being facetious. If you take the last line in the post out of context it seems to contradict the everything we are taught, i.e. write less code to do more.

          • http://davybrion.com Davy Brion

            that pretty much happens with everything you take out of context ;)

            in this case, it means that it does less from an overhead point-of-view… could be more important than you think down the line

  • http://blog.kellybrownsberger.com Kelly Brownsberger

    This is a nice technique… this seriously simplifies a lot of the things I’ve been grappling with today. If only there were magic-string-less FluentAPI for projecting to your DTO’s (a la AutoMapper)… wouldn’t be hard to create one of those.

    Thanks for writing this up

  • Pingback: DTO’s Should Transfer Data, Not Entities