1110
1110

Reputation: 6829

How to write custom methods when using generic repository

I am still struggling to make good data access layer for asp mvc application and as always something is missing :)
I have created separate assembly for DAL and I am using repository pattern and ninject for IOC.
Problem is that now I don't know how to write custom methods (methods out of generic CRUD methods).
This is implementation:
Context class:

public class MainContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IMainContext
    {
        public MainContext()
            : base("DefaultConnection")
        {
        }
        ...
        public DbSet<Country> Countries { get; set; }
        ...
        public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
        {
            return base.Set<TEntity>();            
        }

Repository:

public interface ICountryRepository : IGenericRepository<Country>...

Generic Repository:

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        private readonly IMainContext _context;
        private readonly IDbSet<TEntity> _dbSet;

        public GenericRepository(IMainContext context)
        {
            this._context = context;
            this._dbSet = context.Set<TEntity>();
        }
        ...

Generic Repository Interface:

public interface IGenericRepository<TEntity> where TEntity : class
    {
        IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "");

        TEntity GetByID(object id);

        void Insert(TEntity entity);

        void Delete(object id);

        void Delete(TEntity entityToDelete);

        void Update(TEntity entityToUpdate);
    }

And this is try to add custom method in repository class:

public virtual IEnumerable<Country> GetByLocation(float location)
        {
            var data = from c in _context...
            return data;
        }

But I don't have a context.
I don't know how to implement getting data now.
Should I inject it somehow or make instance by new keyword (but I guess this is wrong)
How to implement custom method now?

Upvotes: 2

Views: 3374

Answers (1)

rleffler
rleffler

Reputation: 470

Your implementation of ICountryRepository should inherit the GenericRepository. The GenericRepository has a reference to the db context which you can use for your custom queries. For your Generic Repository constructor is will be much easier to take MainContext instead of an IMainContext which is ok if you keep injecting it down through you layers. With Ninject you will want to bind your MainContext like this:

kernel.Bind<MainContext>().ToSelf().InRequestScope();

and the rest of your interfaces to the concrete implementation. So each of your repositories will have the context through the GenericRepository which has a reference to your db context which you can make custom queries off of in the repository. If you had a service layer, inject the interface of the repository:

private readonly ICountryRepository _repository;

public SomeServie(ICountryRepository repository){
   _repository = repository;
}

public void DoSomething(float locationId){
   _repository.GetByLocation(locationId);
}

HERE IS THE OTHER CODE YOU NEED:

 public class CountryRepository : GenericRepository<Country>, ICountryRepository
    {

        public CountryRepository(MainContext mainContext) : base(mainContext) { }

        public IEnumerable<Country> GetByLocation(float location)
        {
            return this.Context.Countries.ToList();
        }

.....

 public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        public MainContext Context { get; set; }
        public IDbSet<TEntity> DbSet { get; set; }

        public GenericRepository(MainContext context)
        {
            Context = context;
            DbSet = context.Set<TEntity>();
        }

.......

Also, your GetCountries does not need to be virtual. The main changes here are that you need to pass the context through the country repository constructor to base, and the context and countries db set need to be public, even when inherited. See this article: Are private members inherited in C#?

Upvotes: 3

Related Questions