The conception, birth, and first steps of an application named Charlie

Subscribe: Atom or RSS

The Valley of Data Access - Part 4

by Alister Jones (SomeNewKid)

In the previous weblog entry I set out the plan of how I would refactor the database access code. I am pleased to say that, with just one variation, the refactoring went as planned.

The variation was reasonably cosmetic. In the original plan, the Mapper would gather together the raw query text and a collection of parameters, and pass them off to the new Helper class. This plan was a little short-sighted, as future developments may mean that the Mapper wants to pass the name of a stored procedure to its Helper class, rather than pass the raw query text. So, to allow for future flexibility, I created a new EntityCommand class that looks like this:

namespace Charlie.Framework.Persistence
{
    public class EntityCommand
    {
        public String CommandText
        {
            get
            {
                return this.commandText;
            }
            set
            {
                this.commandText = value;
            }
        }
        private String commandText;

        public EntityParameterCollection Parameters
        {
            get
            {
                return this.parameters;
            }
        }
        private EntityParameterCollection parameters = 
            new EntityParameterCollection();
    }
}

So, rather than passing the raw query text and parameters to its Helper, the Mapper passes a high-level EntityCommand object. In the future, I can extend this EntityCommand object to expose a CommandType property, allowing the Mapper to tell its Helper that a stored procedure is to be used.

With the refactoring complete, the long Retrieve method shown in the second entry in this series has been reduced to this:

public override Entity Retrieve(Entity entity, EntityCriteria crit)
{
    NoteCriteria criteria = (NoteCriteria)crit;

    EntityCommand command = new EntityCommand();
    command.CommandText =
          @"SELECT
                s.Note_Id, 
                Note_CreatedBy, 
                Note_CreationDate, 
                Note_UpdateDate, 
                NoteLocalized_Title, 
                NoteLocalized_Content
            FROM
                Charlie_Note s
            INNER JOIN
                    Charlie_NoteLocalized sc
                ON
                    s.Note_Id = sc.Note_Id
            WHERE
                s.Note_Id = @noteid
            AND
                sc.NoteLocalized_Culture = @culture";
    command.Parameters.Add("@noteid", criteria.Id);
    command.Parameters.Add("@culture", criteria.Culture);

    Note note = (Note)this.Helper.Retrieve(
                entity, criteria, command, this.CreateNoteFromReader);

    return note;
}

All of the red code has been moved out to the Helper class. Better yet, all that red code is shared amongst all of the Mapper classes, where before it was duplicated across those classes.

The second-last line of code includes a delegate that points to the following method of the Mapper:

private Entity CreateNoteFromReader(IDataReader reader)
{
    Note note = new Note();
    note.Title = Convert.ToString(reader["NoteLocalized_Title"]);
    note.Content = Convert.ToString(reader["NoteLocalized_Content"]);
    note.CreationDate = Convert.ToDateTime(reader["Note_CreationDate"]);
    note.UpdateDate = Convert.ToDateTime(reader["Note_UpdateDate"]);
    return note;
}

What you may notice is that the only code that is left in the Mapper is the code that actually does the mapping of the database fields to the business object properties. Everything else has been relocated to the Helper class. If I was an OOP nerd, I might suggest that the cohesion of the class has been increased. But as I am an OOP newbie, I’ll just say that the class is now simpler.

The exercise of refactoring the database access code did bring to light a weakness with Charlie, which is actually a weakness with me. The code in the RoleMapper class could not be refactored to the new system, because its Retrieve method hits the database three times, whereas all other Retrieve methods hit the database one time. The only reason the code hits the database three times is because I could not figure out a more effective SQL command.

So guess what I’m going to learn next?

by Alister Jones | Next up: Charlie Wears Lead Boots

0 comments

----