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.
Pingback: The Morning Brew - Chris Alcock » The Morning Brew #677
Pingback: DTO’s Should Transfer Data, Not Entities