Wednesday, January 13, 2010

Agile Ado.Net Persistence Layer Part 2: Use DTOs (Data Transfer Objects)

What container are we going to use to pass data between the layers of our application?  The usual answers I hear are either DataTables/DataSets or full business objects.  I don’t like any of these options. DataSets and DataTables come with significant overhead and they don’t contain strongly typed data.  Business objects do contain strongly typed data, but they typically contain a lot of extra business logic that I don’t need, and they may even contain persistence logic.  I don’t want any of that.  I want the lightest weight, simplest possible container that will give me strongly typed data, and that container is a Data Transfer Object (DTO). DTOs are simple classes that contain only properties.  They have no real methods, just mutators and accessors for their data. Below is a class diagram for several DTO classes.  You’ll notice that each one has only properties and a constructor, no other logic at all.

image

So I’m going to have a strongly typed DTO class for each “data shape” that needs to go in or out of my BAL.  This concept of a data shape is something that will come up again and it’s actually pretty central to how I’ve designed this architecture.  For now just know that a data shape is a DTO.

DTO, List<DTO>, DataPage<DTO>, and string

Sometimes getting a single DTO will be good enough. For example, when I want to get a single BlogPost, code like the following works just fine.

BlogService service = new BlogService();

BlogPost latestPost = service.GetMostRecentBlogPost();

But most of the time I’m going to be dealing with collections of objects.  The collection of choice is a generic list, List<T>, where T is my DTO type.  So if I need to get a collection of all BlogPosts, that data would come back to me as a List<BlogPost> as shown below.

BlogService service = new BlogService();

List<BlogPost> list = service.GetListOfAllBlogPosts(BlogPostSortOption.ByDate);

So between single DTO and List<DTO>, we’ve got most of our data needs covered but there’s still a couple more.  What about paging?  Take the example above.  There’s no way that I’m ever going to get a list of all BlogPosts and display it all at once.  I’m going to break it up into pages.  What I need is a generic DataPage<T> class that I can use to encapsulate a single page of data along with some metadata like PageSize and PageIndex. The DataPage class is defined in our Common assembly.

public class DataPage<T>

{

    public List<T> Data = new List<T>();

    public int RecordCount = 0;

    public int PageSize = 20;

    public int PageIndex = 0;

    public int PageCount { get{ return (RecordCount ==0 || PageSize==0) ? 0

                         : (RecordCount + PageSize - 1) / PageSize;}}

}

It’s a pretty simple class.  Note the very concise algorithm for calculating PageCount.  That isn’t mine, I picked it up on some website but I can’t remember where.  Anyway it works really well.  So now that we have our DataPage<T> defined in the Common assembly, if we want to divide our BlogPosts up into pages of 20, and we want to get the third page, we’ll use code like this.

BlogService service = new BlogService();

int pageSize = 20;

int pageIndex = 2;

DataPage<BlogPost> page = service.GetPageOfAllBlogPosts(pageSize, pageIndex, BlogPostSortOption.ByDate);

We’ll see later on that having this simple DataPage<T> class really makes paging easy to deal with.  Now we’ve almost got all of our bases covered, but there’s one more input/output type that we need to consider, a simple string value.  At some point we’re going to want to get a simple value out of our persistence layer.  If we don’t think of it ahead of time we’ll be tempted to do something silly like create a DTO class that contains a single string field, not I would ever do something like that … at least not again.  Anyway, we will want to get a simple value at some point. Let’s just plan for it now and require that our persistence layer has the capability to return string values.  

Next time, a look at Service classes and query logic

So, we haven’t written any actual persistence code yet, but we know a lot about how our persistence layer is going to behave.  We know that all data going in or out of our BAL is going to be in the shape of a single DTO, a List<DTO>, a DataPage<DTO>, or a string value.  We also have some sample code that demonstrates how we expect our service classes to work.  By the way, this isn’t just a case of hindsight being 20/20.  When designing code I’ll typically write the consuming code first, because it really guides my development of the lower level framework code and sets up requirements for how that code will need to behave.  Next time we’ll continue this top down approach and write a service class.

Next Post: Agile ADO.Net Persistence Layer Part 3: Service Class Single<DTO> Data Access Method

2 comments:

  1. I have been studying different persistence techniques for sometime. Your approach seems very clean. I can't wait for the rest of the articles. I am really interested in the code for the DAO especially how to return a DataPage. When can we expect the rest?

    Thanks so much

    ReplyDelete
  2. I was going to take a few posts to explore the service classes but maybe I'll skip ahead and get to the DAO and DataMappers. I'm also going to put together a sample MVC app that I'll publish up on codeplex.

    ReplyDelete