Thursday, February 11, 2010

Data Access Layer in C# using Repository and Data Mapper – Part 2


As mentioned in the previous post Data Mapper is a layer to hide database access from your domain objects. As a recommendation data mapper should not be exposed to the business logic layer. All calls to the data mapper should be routed via a Repository that should make use of the data mapper for object creation. The data mapper will have access to the domain model/ entities for object creation. In this post, we’ll see how to create a data mapper implementation in C#.
Before looking into the data mapper, we’ll create our first business entity, Customer. Every business entities in our sample inherit from a base entity that holds the common properties for key, versioning and tracking. The Customer entity is defined as
public class BaseEntity
{
    public T Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ChangedDate { get; set; }
    public byte[] Version { get; set; }
}
public class Customer  :BaseEntity<long>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
}
All the business entities should be part of the domain model and is defined in separate assembly. In this sample, I have created a class library (DataMapper.DomainObjects) to define the business entities.
Once the entities are ready, we can work on the base mapper for all entities. For convenience I have defined the data mappers and repositories in another class library (DataMapper.ResourceAccess)



The Base mapper defines an abstract method Construct that should be implemented by all the entity specific mappers for mapping the relational database fields to the object properties. The constructcommonData method populates the baseEntity properties.

    public abstract T Construct(IDataRecord record);

    public IList ConstructCollection(IDataReader reader)
    {
        List entityCollection = new List();
        while (reader.Read())
        {
            entityCollection.Add(Construct(reader));
        }
        return entityCollection;
    }

    protected T ConstructCommonData(IDataRecord record)
    {
        T baseEntity = new T();

        int index = record.GetOrdinal(___KeyField);
        if (record.IsDBNull(index)) throw new ArgumentException("Failed to map the key field");
        baseEntity.Id = (Key)record.GetValue(index);

        index = record.GetOrdinal("CreatedDate");
        baseEntity.CreatedDate = record.IsDBNull(index) ? DateTime.MinValue : record.GetDateTime(index);

        index = record.GetOrdinal("ChangedDate");
        baseEntity.ChangedDate = record.IsDBNull(index) ? DateTime.MinValue : record.GetDateTime(index);

        index = record.GetOrdinal("Version");
        if (!record.IsDBNull(index))
        {
            baseEntity.Version = new Byte[(record.GetBytes(index, 0, null, 0, int.MaxValue))];
            record.GetBytes(index, 0, baseEntity.Version, 0, baseEntity.Version.Length);
        }        
        return baseEntity;
    }


Download the complete class file here
Next we’ll see how to implement the Customer data mapper for the Customer entity created in the sample.

5 comments:

Anonymous said...

The link for the code is no more available.Can you please share the code.

Sathish G said...

Can you please share the code.Its very interesting.

amexn said...

please share the code

amexn said...

please share the code

Prajeesh Prathap said...

I would suggest to use the version with EF 5.0 or Entity framework..

http://blogsprajeesh.blogspot.com/2010/05/data-access-application-block-50-part-1.html
http://blogsprajeesh.blogspot.com/2010/11/entity-framework-creating-generic_30.html