1
\$\begingroup\$

Almost all of generic repository pattern tutorials were making use of EF, so I haven't got much sources to compare my code with. Here is what I have done. Could you please suggest me to fix my wrongs if I have or improve the code?

Note: I am using Dapper.Net as ORM, and I am aware of Dapper.Contrib dll, I just want to implement my own methods.

Generic Repository class

public interface IRepository<T> where T : BaseEntity
{
    IDbConnection Connection { get; set; }
    void Insert(T entity);
    void Delete(T entity);
    T GetById(int id);
    IQueryable<T> GetAll();
}

A Repository Class

public interface ICustomerRepository : IRepository<Customer>
{

}

public class CustomerRepository : ICustomerRepository
{
    public IDbConnection Connection { get; set; }

    public CustomerRepository()
    {
        Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ConnectionString);
    }

    public void Delete(Customer entity)
    {
        try
        {
            using (Connection)
            {
                Connection.Execute("DELETE FROM dbo.Customer Where Id = @Id", new { entity.Id });
            }
        }
        catch (Exception ex)
        {

        }
    }

    public IQueryable<Customer> GetAll()
    {
        IQueryable<Customer> list = new List<Customer>().AsQueryable();

        try
        {
            using (Connection)
            {
                list = Connection.Query<Customer>("SELECT * FROM dbo.Customer").AsQueryable();
            }
        }
        catch (Exception ex)
        {

        }
        return list;
    }

    public Customer GetById(int id)
    {
        Customer customer = new Customer();
        try
        {
            using (Connection)
            {
                customer = Connection.Query<Customer>("SELECT * FROM dbo.Customer WHERE Id = @Id", new { Id = id }).SingleOrDefault();
            }
        }
        catch (Exception ex)
        {

        }
        return customer;
    }

    public void Insert(Customer entity)
    {
        try
        {
            using (Connection)
            {
                Connection.Execute("INSERT INTO dbo.Customer VALUES(@FullName, @TcNo, @BirthDate)",
                    new
                    {
                        entity.FullName,
                        entity.Tcno,
                        entity.BirthDate
                    });
            }
        }
        catch (Exception ex)
        {

        }
    }
}

An Api Controller

public class CustomerController : ApiController
{
    private IRepository<Customer> _customerRepo;

    public CustomerController()
    {
        _customerRepo = new CustomerRepository(new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ConnectionString));
    }
    [HttpGet]
    [Route("")]
    public IHttpActionResult Get()
    {
        return Json(_customerRepo.GetAll());
    }
}
\$\endgroup\$
  • 5
    \$\begingroup\$ Why did you decide to ignore all exceptions? Don't you want to know what went wrong? \$\endgroup\$ – t3chb0t Oct 10 '17 at 6:46
  • \$\begingroup\$ Actually those blocks are not implemented yet. I will just simply log the exceptions. If you have any suggestion on this I would love to know. \$\endgroup\$ – ibubi Oct 10 '17 at 7:00
  • \$\begingroup\$ Normally a Generic Repository has also an Update Method. And if you add this Method, you should think about adding a locking mechanism (optimistic or pessimistic) if you have a multi user environment. \$\endgroup\$ – Volkmar Rigo Oct 10 '17 at 14:25
  • \$\begingroup\$ @VolkmarRigo isn't the UoW responsibility to handle transactions? \$\endgroup\$ – Adrian Iftode Oct 10 '17 at 18:56
  • \$\begingroup\$ @AdrianIftode since this repository is used in an API Controller, reading an entity and updating/deleting an entity are 2 different service calls. Therefore normally you have to add some logic to assure, that you update/delete an entity only if the entity wasn't changed by someone else after you read it. \$\endgroup\$ – Volkmar Rigo Oct 11 '17 at 9:56
2
\$\begingroup\$

I think you are in the right direction but let me suggest some things.

Remove the try catch and let the repository throw or catch and throw your own exception.

Inject IDbConnection in the constructor of the repository and remove the using on the repository methods

    private IDbConnection _connection;

    public CustomerRepository(IDbConnection connection)
    {
        _connection = connection;
    }

Probably you want to use the repository in this way in many scenarios and with your current implementation you loose the transaction scope

    public void DoWork()
    {
        using (var connection = ...)
        {
            //begin transaction
            var repository = new CustomerRepository(connection);
            var otherRepository = new OtherRepository(connection)
            var customer = repository.GetById(2);
            //do some stuff
            otherRepository.Update()...
            repository.Delete(customer);
            //commit transaction
        }
    }

This can be combined with IoC container.

\$\endgroup\$
  • \$\begingroup\$ I was thinking of moving try-catchto up level (controllers), thanks. Btw, I updated the question, added controller side which calls the repo classes. I think it is still not transaction-friendly, is it? I should consider the way you did that create dowork method and wrap it with a single connection for transactions inside all actions in my controllers if needed. \$\endgroup\$ – ibubi Oct 10 '17 at 9:47
  • 1
    \$\begingroup\$ Not only transactions, but I guess if you do two calls to the repository it will fail as conection is disposed. Your controller looks good. Consider wire all the things with an IoC container as MVC plays very good with it. Enjoy :) \$\endgroup\$ – ogomrub Oct 10 '17 at 10:25
  • \$\begingroup\$ I had to have a break for a while, now I am onto this again, I wonder how to combine transactions via IoC container. Because, I am using Unity for IoC currently. Do you have any tutorial or guidence for this? \$\endgroup\$ – ibubi Oct 18 '17 at 6:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.