Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

Monday, November 1, 2010

Creating a loosely coupled event publish/ subscribe framework for Silverlight

Applications need a loosely coupled event publishing and subscribing mechanism for communication between entities that don't have a direct reference to each other. In this post I will show how to create an Event aggregator model that can be used in our applications. The sample that is used in this post is from a Silverlight application I was working with. The EventManager class is responsible for registration and invoking of events based on a publish/ subscribe pattern.


public class EventManager
{
    public static void Subscribe(ViewModelBase reciever, string key, Action action)
    {
        EventHolder newEventHolder = new EventHolder(reciever, action);
        var eventHoldersForEventId = Singleton<List<KeyValuePair<string, List>>>>.Instance;

        if (eventHoldersForEventId.Any(x => x.Key == key))
        {
            var keyValuePair = eventHoldersForEventId.First(x => x.Key == key);
            var eventHolder = keyValuePair.Value.FirstOrDefault(x => x.ViewModel.ToString() == reciever.ToString() && x.InvokeEvent == action);
            if (eventHolder == default(EventHolder))
                keyValuePair.Value.Add(new EventHolder(reciever, action));
        }
        else
        {
            eventHoldersForEventId.Add(new KeyValuePair<string, List>>(key, new List>()));
            var KeyValuePair = eventHoldersForEventId.First(x => x.Key == key);
            KeyValuePair.Value.Add(newEventHolder);
        }
    }

    public static void Publish(string key, T data)
    {
        var eventHoldersForEventId = Singleton<List<KeyValuePair<string, List>>>>.Instance;

        if (eventHoldersForEventId.Any(x => x.Key == key))
        {
            var keyValuePair = eventHoldersForEventId.First(x => x.Key == key);
            var eventHolderCollection = keyValuePair.Value;
            eventHolderCollection.ForEach(x => x.InvokeEvent.Invoke(data));
        }
    }
}

The objects that are interested in listening to events can register themselves using a Subscribe method.
The subscribe method needs an instance of the object and a delegate to invoke when the event occurs.
Publish method is used by objects to notify an event.
public class EventHolder
    {
        public EventHolder(ViewModelBase viewModel, Action action)
        {
            ViewModel = viewModel;
            InvokeEvent = action;
        }

        public ViewModelBase ViewModel { get; private set; }
        public Action InvokeEvent { get; private set; }
    }

    public class EventHolder
    {
        public EventHolder(ViewModelBase viewModel, Action action)
        {
            ViewModel = viewModel;
            InvokeEvent = action;
        }

        public ViewModelBase ViewModel { get; private set; }
        public Action InvokeEvent { get; private set; }
    }
}

Events can be registered or subscribed by using
private void SubscribeToEvent()
{
    //TargetMessenger.Subscribe(this, (x) => _projectId = x);
           
    EventManager.Subscribe<int>(this, EventTopics.PUBLISH_PROJECTID_TO_MANAGEUSER, (data) =>
    {
        _projectId = data;
    });
}

Event publication is done as
EventManager.Publish<int>(EventTopics.PUBLISH_PROJECTID_TO_MANAGEUSER, projectId);

Singleton is a generic class for creating singleton objects
public class Singleton where T : new()
{
    Singleton() { }

    public static T Instance
    {
        get
        {
            if(_initializer == default(Lazy)) _initializer = new Lazy();
            return _initializer.Value;
        }
    }
    static Lazy _initializer = default(Lazy);
}

Friday, February 12, 2010

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


The customer repository inherits the base repository and uses the data mapper instance for object creation. All the CRUD procedures defined in the first post of this series are called in this class. The query for accessing and persisting data in the relational model is formed in the Customer repository.
protected override BaseMapper<Customer, long> Mapper
{
    get
    {
        if (___Mapper == default(CustomerMapper)) ___Mapper = new CustomerMapper("CustomerIntId");
        return ___Mapper;
    }
}

public Customer GetById(long id)
{
    DbCommand command = ___Database.GetStoredProcCommand("usp_GetCustomerById");
    ___Database.AddInParameter(command, "CustomerIntId", DbType.Int64, id);
    return FindOne(command);
}

public void Insert(Customer entity)
{
    DbCommand command = ___Database.GetStoredProcCommand("usp_InsertCustomer");
    ___Database.AddInParameter(command, "FirstName", DbType.String, entity.FirstName);
    ___Database.AddInParameter(command, "LastName", DbType.String, entity.LastName);
    ___Database.AddInParameter(command, "Address", DbType.String, entity.Address);

    ___Database.AddOutParameter(command, "CustomerIntId", DbType.Int64, 8);

    ___Database.ExecuteNonQuery(command);

    Int64 customerIntId = (Int64)(___Database.GetParameterValue(command, "CustomerIntId"));
    entity.Id = customerIntId;
}

public void Remove(long id)
{
    DbCommand command = ___Database.GetStoredProcCommand("usp_DeleteCustomerById");
    ___Database.AddInParameter(command, "CustomerIntId", DbType.Int64, id);

    ___Database.ExecuteNonQuery(command);
}
I have uploaded the source code for the customer repository here.
[TestMethod]
public void can_insert_customers_into_db()
{
    ICustomerRepository repository = new CustomerRepository();
    var customerToInsert = new Customer { FirstName = "Prajeesh", LastName = "Prathap", Address = "BTM 2nd Stage, Bangalore" };
    repository.Insert(customerToInsert);

    var customer = repository.GetById(customerToInsert.Id);
    Assert.IsNotNull(customer);
    Assert.AreEqual<string>(customer.FirstName, "Prajeesh");

    repository.Remove(customer.Id);
}
Our final implementation looks like.

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


Mapping the data elements in the domain model and relational model for the customer entity functionality is implemented as part of the CustomerMapper class which inherits from the BaseMapper created in the previous sample. The customer mapper class contains code to convert data between these data models.
public override Customer Construct(IDataRecord record)
{
    Customer customer = ConstructCommonData(record);

    int index = record.GetOrdinal("FirstName");
    customer.FirstName = record.IsDBNull(index) ? string.Empty : record.GetString(index);
    index = record.GetOrdinal("LastName");
    customer.LastName = record.IsDBNull(index) ? string.Empty : record.GetString(index);
    index = record.GetOrdinal("Address");
    customer.Address = record.IsDBNull(index) ? string.Empty : record.GetString(index);

    return customer;
}
The overridden Construct method is responsible for this data conversion. Once the data mapper is ready, we’ll use this in the repository for data access. The data mapper is not exposed outside the repository.
Creating the repository for the sample
Martin fowler writes:
"A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers."
Each entity in a domain layer defines a repository for data access operations. In our sample we have one entity (Customer). We’ll define a repository for the customer entity and write some test cases to demonstrate the functionality. The repository interface defines the CRUD operations required for our sample.
    T GetById(Key id);
    IList GetAll();
    void Insert(T entity);
    T Update(T entity);
    void Remove(Key id);
I have created a base repository class which will be used as the base class for entity specific repositories and implements the common functionality.
    protected T FindOne(DbCommand command)
    {
        T entity = new T();
        using (IDataReader reader = ___Database.ExecuteReader(command))
        {
            if (reader.Read())
                entity = Mapper.Construct(reader);
        }
        return entity;
    }

    protected IList Find(DbCommand command)
    {
        IList entityCollection = default(List);
        using (IDataReader reader = ___Database.ExecuteReader(command))
        {
            entityCollection = Mapper.ConstructCollection(reader);               
        }
        return entityCollection;
    }

The source for BaseRepository can be downloaded from this link
Next we’ll create the customer repository.

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.

Wednesday, February 10, 2010

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


Data access is a popular subject in most of the applications. There are plenty of options on various data access techniques and frameworks that often create confusion in the minds of developers choosing the right approach or strategy for creating an effective data access layer. Two main things that should be considered while creating a data access layer are simplicity and reliability.
When creating an application with a domain model, one should consider the usage of a layer that is used to map objects in the domain model to the relational table schema while keeping them independent of each other. The main objective of the data mapper is to strip the responsibility of persistence from the entity objects in favor of classes external to the entities. The repository uses this data mapper classes to access, modify and persist these entities back to the database. A repository is a layer that mediates between the business entities and data mappers in your data access code. The business layer uses this repository for all the data access functionality it requires.
In this article series we’ll see how to create a simple data access layer in C# that uses the data mapper and repository pattern implementation. The database used in the sample is SQL Server, which can be replaced by any other relational database. I have used the enterprise library data access application block for all ADO.NET queries.
Before writing the C# code, we’ll work on the database schema. We’ll use a customer table and the CRUD procs to demonstrate the repository and data mapper sample in this article series.
The scripts for creating the customer table is
CREATE TABLE [dbo].[Customers](
      [CustomerIntId] [bigint] IDENTITY(1,1) NOT NULL,
      [FirstName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
      [LastName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
      [Address] [varchar](500) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
      [CreatedDate] [datetime] NULL,
      [ChangedDate] [datetime] NULL,
      [Version] [timestamp] NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
(
      [CustomerIntId] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Stored procedures used in the sample.
CREATE PROCEDURE [dbo].[usp_GetAllCustomers]   
AS
BEGIN
      SET NOCOUNT ON;

      SELECT [CustomerIntId] as 'CustomerIntId'
      ,[FirstName] as 'FirstName'
      ,[LastName] as 'LastName'
      ,[Address] as 'Address'
      ,[CreatedDate] as 'CreatedDate'
      ,[ChangedDate] as 'ChangedDate'
      ,[Version] as 'Version'
      FROM [dbo].[Customers]
END
CREATE PROCEDURE [dbo].[usp_GetCustomerById]
      @CustomerIntId bigint
AS
BEGIN
      SET NOCOUNT ON;

    SELECT [CustomerIntId] as 'CustomerIntId'
      ,[FirstName] as 'FirstName'
      ,[LastName] as 'LastName'
      ,[Address] as 'Address'
      ,[CreatedDate] as 'CreatedDate'
      ,[ChangedDate] as 'ChangedDate'
      ,[Version] as 'Version'
  FROM [dbo].[Customers]
  WHERE [CustomerIntId] = @CustomerIntId
END
CREATE PROCEDURE [dbo].[usp_InsertCustomer]
      @FirstName varchar(50),
      @LastName varchar(50),
      @Address varchar(500),
      @CustomerIntId bigint OUT
AS
BEGIN
      SET NOCOUNT ON;

      INSERT INTO [dbo].[Customers]
           ([FirstName]
           ,[LastName]
           ,[Address]
           ,[CreatedDate]
           ,[ChangedDate])
     VALUES
           (@FirstName
           ,@LastName
           ,@Address
           ,getdate()
           ,getdate())

      SET @CustomerIntId = SCOPE_IDENTITY()
END
CREATE PROCEDURE [dbo].[usp_UpdateCustomer]
      @CustomerIntId bigint,
      @FirstName varchar(50),
      @LastName varchar(50),
      @Address varchar(500),
      @Version timestamp,
      @VersionNew timestamp OUT
AS
BEGIN
      SET NOCOUNT ON;

    UPDATE [dbo].[Customers]
      SET [FirstName] = @FirstName
      ,[LastName] = @LastName
      ,[Address] = @Address
      ,[ChangedDate] = getdate()
      WHERE CustomerIntId = @CustomerIntId
      AND Version = @Version

      IF @@ROWCOUNT = 0
      BEGIN
            RAISERROR('Concurrent update error. Updated aborted.', 16, 2)
      END

      SELECT @VersionNew = [Version]      FROM [dbo].[Customers]
      WHERE [CustomerIntId] = @CustomerIntId   
END
CREATE PROCEDURE [dbo].[usp_DeleteCustomerById]
      @CustomerIntId bigint
AS
BEGIN
      SET NOCOUNT ON;

    DELETE FROM [dbo].[Customers]
    WHERE [CustomerIntId] = @CustomerIntId
END
Next we’ll see how to create a data access layer for accessing the Customer data that we created in the database.