Udemy

Implementing Repository pattern and Dependency Injection in ADO.net using Generics in C#

Friday, September 04, 2015 0 Comments A+ a-

Nowadays i am trying to learn different design patterns in object oriented paradigm that are pretty useful to implement generic solutions for different scenarios, few weeks back for a job hunt i got an assignment to do which was a web application which would interact with database, so i took it as a challenge and decided to make it loosely coupled using design patterns which were applicable in that scenario.

One of them which implemented in my assignment is repository pattern using generics and with that Dependency Injection using which i injected dependencies of Repository class via constructor.
 


I made generic class which would be inherited by other types against the different tables in the application. in this class i have used different framework features like Reflection and Generics.


My generic class is an abstract class, so it needs to be inherited for making use of it, you will see next how we will use it.


Here is the Repository class:

public abstract class Repository<TEntity> where TEntity : new()
{
    DbContext _context;

    public Repository(DbContext context)
    {
        _context = context;
    }

    protected DbContext Context 
    { 
        get
        {
          return this._context;
        } 
    }

    protected IEnumerable<TEntity> ToList(IDbCommand command)
    {
        using (var record = command.ExecuteReader())
        {
            List<TEntity> items = new List<TEntity>();
            while (record.Read())
            {
                    
                items.Add(Map<TEntity>(record));
            }
            return items;
        }
    }

        
    protected TEntity Map<TEntity>(IDataRecord record)
    {
        var objT = Activator.CreateInstance<TEntity>();
        foreach (var property in typeof(TEntity).GetProperties())
        {
            if (record.HasColumn(property.Name) && !record.IsDBNull(record.GetOrdinal(property.Name)))
                property.SetValue(objT, record[property.Name]);


        }
        return objT;
    }


}

Now i have table in database User whose schema is :

CREATE TABLE [dbo].[tblUser] (
    [UserID]    INT           IDENTITY (1, 1) NOT NULL,
    [FirstName] NVARCHAR (25) NULL,
    [LastName]  NVARCHAR (25) NULL,
    [UserName]  NVARCHAR (25) NULL,
    [Password]  NVARCHAR (25) NULL,
    [IsActive]  BIT           NULL,
    [IsDeleted] BIT           NULL,
    [CreatedBy] INT           NULL,
    [CreatedAt] DATETIME      NULL,
    [UpdatedBy] INT           NULL,
    [UpdatedAt] DATETIME      NULL,
    [Email]     NVARCHAR (50) NULL,
    PRIMARY KEY CLUSTERED ([UserID] ASC)
);



Against this table i have Model class for mapping from table to that type which looks :

public class User
{
    public int UserID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string UserName { get; set; }

    public string Password { get; set; }

    public bool IsActive { get; set; }

    public bool IsDeleted { get; set; }

    public DateTime CreatedAt { get; set; }

    public int CreatedBy { get; set; }

    public DateTime UpdatedAt { get; set; }

    public int UpdatedBy { get; set; }

    public string Email { get; set; }
}

We want to fetch data from User table for which we will create a Repository class for User type and the we will write implementation to fetch records from User table from database. Our all methods that need to get data, insert data,update data or delete data from User table will reside in the UserRepository class.

Here is the implementation of User Repository class:

public class UserRepository : Repository<User>
{
    private DbContext _context;
    public UserRepository(DbContext context)
        : base(context)
    {
        _context = context;
    }


    public IList<User> GetUsers()
    {
        using (var command = _context.CreateCommand())
        {
            command.CommandText = "exec [dbo].[uspGetUsers]";

            return this.ToList(command).ToList();
        }
    }

    public User CreateUser(User user)
    {
        using (var command = _context.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "uspSignUp";

            command.Parameters.Add(command.CreateParameter("@pFirstName", user.FirstName));
            command.Parameters.Add(command.CreateParameter("@pLastName", user.LastName));
            command.Parameters.Add(command.CreateParameter("@pUserName", user.UserName));
            command.Parameters.Add(command.CreateParameter("@pPassword", user.Password));
            command.Parameters.Add(command.CreateParameter("@pEmail", user.Email));

            return this.ToList(command).FirstOrDefault();


        }

    }


    public User LoginUser(string id, string password)
    {
        using (var command = _context.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "uspSignIn";

            command.Parameters.Add(command.CreateParameter("@pId", id));
            command.Parameters.Add(command.CreateParameter("@pPassword", password));

            return this.ToList(command).FirstOrDefault();
        }
    }


    public User GetUserByUsernameOrEmail(string username, string email)
    {
        using (var command = _context.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "uspGetUserByUsernameOrEmail";

            command.Parameters.Add(command.CreateParameter("@pUsername", username));
            command.Parameters.Add(command.CreateParameter("@pEmail", email));

            return this.ToList(command).FirstOrDefault();
        }
    }


}


We are done for the UserRepository for new, i have added methods are wrote Stored Procedure to complete the assignment and now i will tell how to make use of it in the Service Layer or in Business Rule to do operations.




First create an interface namely IUserService:

[ServiceContract]
public interface IUserService
{

    [OperationContract]
    IList<User> GetUsers();

    [OperationContract]
    User RegisterUser(User user);

    [OperationContract]
    User Login(string id, string password);

    [OperationContract]
    bool UserNameExists(string username, string email);


}


Here is my WCF Service for User that calls the UserRepository for doing operations:

public class UserService : IUserService
{
    private IConnectionFactory connectionFactory;

    public IList<User> GetUsers()
    {
        connectionFactory = ConnectionHelper.GetConnection();

        var context = new DbContext(connectionFactory);

        var userRep = new UserRepository(context);

        return userRep.GetUsers();
    }

    public User RegisterUser(User user)
    {
        connectionFactory = ConnectionHelper.GetConnection();

        var context = new DbContext(connectionFactory);

        var userRep = new UserRepository(context);

        return userRep.CreateUser(user);
    }


    public User Login(string id, string password)
    {
        connectionFactory = ConnectionHelper.GetConnection();

        var context = new DbContext(connectionFactory);

        var userRep = new UserRepository(context);

        return userRep.LoginUser(id, password);
    }

    public bool UserNameExists(string username, string email)
    {
        connectionFactory = ConnectionHelper.GetConnection();

        var context = new DbContext(connectionFactory);

        var userRep = new UserRepository(context);

        var user = userRep.GetUserByUsernameOrEmail(username, email);
        return !(user != null && user.UserID > 0);

    }
}

You can see that when creating instance of UserRepository i am injecting database context via constructor and then i am calling different methods from userReposiory according to need.

Now in future when i add another table in database, i would create another Repository type and implement its Data Access logic and will call it same way, so applying Dependency Injection and Repository pattern we are following DRY principle to some extent, but i am sure we can make it more better than this.
Coursera - Hundreds of Specializations and courses in business, computer science, data science, and more