2

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?

1110
  • 7,829
  • 55
  • 176
  • 334

1 Answers1

3

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#?

Community
  • 1
  • 1
rleffler
  • 430
  • 6
  • 15
  • Yes I understand that and that's why `ICountry` inherit `GenericRepository` but when I type `this.` there is no context. – 1110 Jul 17 '14 at 20:50
  • But when I change `private readonly _context` to `internal readonly _context` I see it in repository implementation but there are no DBSets anymore. – 1110 Jul 17 '14 at 21:16
  • try making it a DbSet instead of IDbSet – rleffler Jul 17 '14 at 21:28
  • It is Still the same. – 1110 Jul 17 '14 at 21:33
  • Just to make sure, your CountryRepository inherits GenericRepository, not implements IGenericRepository, correct? – rleffler Jul 17 '14 at 21:42
  • Ok when I change `GenericRepository` and concrete repository to use `MainContext` instead of `IMainContext` then I can see DBSets defined in context. I inject it via `kernel.Bind().To().InRequestScope();` what should I do to use interface instead class? – 1110 Jul 18 '14 at 18:59
  • to use IMainContext instead of MainContext? – rleffler Jul 18 '14 at 19:18
  • Yes why with interface I can't see DBSets and with implementation can? – 1110 Jul 18 '14 at 19:21
  • it can make things a bit more complicated, but you should be able to pass in IMainContext to the CountryRepository and pass that to the base, and make the base generic repository constructor take an IMainContext as well. – rleffler Jul 18 '14 at 19:24