I'm refactoring my code and I started by removing a reference to Entity Framework in my service layer. This layer uses unit of work and repositories (through interfaces) located in my DAL layer.
Now I encountered a problem because my base repository class looks like this:
public interface IDatabaseFactory<C> : IDisposable
{
C Get();
void Set(string connectionString);
}
public abstract class Repository<C, T> : IRepository<T>
where C : DbContext, IBaseContext
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
private C dataContext;
protected Repository(IDatabaseFactory<C> databaseFactory)
{
this.DatabaseFactory = databaseFactory;
this.dbset = DataContext.Set<T>();
}
protected IDatabaseFactory<C> DatabaseFactory
{
get;
private set;
}
protected C DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
//etc...
}
I obviously need the DbContext constraint on type C. However, if I do so, I get errors on dataContext because it cannot resolve C in DbContext.
How can I overcome this problem?
EDIT
A typical repository looks like this:
public interface ICustomerTypeRepository : IRepository<CustomerType> { }
public class CustomerTypeRepository : Repository<IBaseContext, CustomerType>, ICustomerTypeRepository
{
public CustomerTypeRepository(IDatabaseFactory<IBaseContext> databaseFactory)
: base(databaseFactory) { }
}
After the changes suggested below, I still get the same errors:
The type 'IBaseContext' cannot be used as type parameter 'TContext' in the generic type or method 'Repository'. There is no implicit reference conversion from 'IBaseContext' to 'System.Data.Entity.DbContext'.
To fix compilation error, you have to put appropriate constraints to your generic types (I've replaced C to TContext for readability):
interface IBaseContext { }
interface IDatabaseFactory<TContext> : IDisposable
where TContext : DbContext
{
TContext Get();
void Set(string connectionString);
}
interface IEntity { }
interface IRepository<T>
where T : class, IEntity
{ }
abstract class Repository<TContext, T> : IRepository<T>
where TContext : DbContext, IBaseContext
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
private TContext dataContext;
protected Repository(IDatabaseFactory<TContext> databaseFactory)
{
this.DatabaseFactory = databaseFactory;
this.dbset = DataContext.Set<T>();
}
protected IDatabaseFactory<TContext> DatabaseFactory { get; private set; }
protected TContext DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
//etc...
}
But from the point of architecture, looks like that holding a reference to DbContext in repository is superfluous. Of course, it is hard to propose better solutiuon without knowledge about all of your types.
For remove DbContext from your code you need change IDatabaseFactory like this:
public interface IDatabaseFactory : IDisposable
{
T Set<T>() where T : IEntity;
}
Then you can change Repository
public abstract class Repository<T> : IRepository<T>
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
protected Repository(IDatabaseFactory databaseFactory)
{
this.dbset = databaseFactory.Set<T>();
}
// other code
}
Implementation of IDatabaseFactory:
public class DatabaseFactory : IDatabaseFactory
{
private readonly DbContext _context;
public DatabaseFactory(DbContext context)
{
_context = context;
}
public T Set<T>() where T : Entity
{
return _context.Set<T>();
}
}
Related
I'm want to use BloggingRepository class inside of CategoryRepository by injection, and accessing the BloggingRepository methods in controllers via CategoryRepository
But I couldn't achive this because I can't access to bloggingRepo field in CategoryController,
So I decided to do it by inheritance.
Due to I'm inexperienced in oop, I will appreciate if you could guide me why this approach not working and what is the appropriate way
In the image the first design is working but the second not
class diagram image
I wanna use the Add method of BloggingRepository in SaveCategory of CategoryController
public interface IBloggingRepository
{
void Add<T>(T entity) where T : class;
void Delete<T>(T entity) where T : class;
Task<bool> SaveAll();
}
public interface ICategoryRepository : IBloggingRepository
{
Task<Category> GetCategory(int id);
}
public class BloggingRepository : IBloggingRepository
{
private readonly DataContext _context;
public BloggingRepository(DataContext context )
{
_context = context;
}
public void Add<T>(T entity) where T : class
{
_context.Add(entity);
}
}
public class CategoryRepository : ICategoryRepository
{
private readonly DataContext _context;
public readonly IBloggingRepository bloggingRepo;
public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository)
{
_context = context;
bloggingRepo = bloggingRepository;
}
}
public class CategoryController : Controller
{
private readonly ICategoryRepository _categoryRepo;
public CategoryController(ICategoryRepository categoryRepo)
{
_categoryRepo = categoryRepo;
}
public async Task<IActionResult> SaveCategory()
{
// _categoryRepo.bloggingRepo.Add();
}
}
//Startup.cs
services.AddScoped<IBloggingRepository, BloggingRepository>();
services.AddScoped<ICategoryRepository, CategoryRepository>();
Your interface should describe all the methods you wish to be exposed. Your interfaces describe what a given class will implement, not how its implemented, thus not exposing the state of the class. This is good as it allows you to have several classes inherit from this interface and implement the same methods in different ways.
In your case, you want the ability to "Add" from your CategoryRepository. Luckily for you, you already have an interface for this, IBloggingRepository.
If you want the same methods found in IBloggingRepository in your ICategoryRepository, just implement that interface as well! Its that easy.
METHOD 1 (does not work):
In this method, the CategoryRepository is going to implement both interfaces, so the CategoryRepository MUST expose the Add method. This also provides the ability to hide the IBloggingRepository from outside the class so that the state is hidden. However, this doesn't work. Why? Only the CategoryRepository class implements both ICategoryRepository and IBloggingRepository. The ICategoryRepository doesn't implement IBloggingRepository, so the Add method is not exposed in the ICategoryRepository interface, and that is what is being used in your controller.
// Implementation of the repository
// Does not expose Add to the ICategoryRepository !!!
public class CategoryRepository : ICategoryRepository, IBloggingRepository
{
private readonly DataContext _context;
private readonly IBloggingRepository _bloggingRepo;
public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository)
{
_context = context;
_bloggingRepo = bloggingRepository;
}
// The implementation of the Add method
public void Add<T>(T entity) where T : class
{
_bloggingRepo.Add(entity);
}
}
METHOD 2 (Correct answer):
In this way, we enforce that EVERY ICategoryRepository made MUST implement the IBloggingRepository. This is different than METHOD 1, as the first method doesn't imply that every ICategoryRepository will implement IBloggingRepostiory.
// Exposes the IBloggingRepository methods to ICategoryRepository
public interface ICategoryRepository : IBloggingRepository
{
}
// Implementation of the repository
public class CategoryRepository : ICategoryRepository
{
private readonly DataContext _context;
private readonly IBloggingRepository _bloggingRepo;
public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository)
{
_context = context;
_bloggingRepo = bloggingRepository;
}
// The implementation of the Add method
public void Add<T>(T entity) where T : class
{
_bloggingRepo.Add(entity);
}
}
DEMONSTRATION:
// Some model to be added to the repository
// Just for demonstration purposes
public class Blog
{
public Blog() { }
}
public class CategoryController : Controller
{
private readonly ICategoryRepository _categoryRepo;
public CategoryController(ICategoryRepository categoryRepo)
{
_categoryRepo = categoryRepo;
}
public async Task<IActionResult> SaveCategory()
{
// _categoryRepo.bloggingRepo.Add();
return await Task.Run(() =>
{
Blog blog = new Blog();
_categoryRepo.Add(blog);
// return IActionResult;
}).ConfigureAwait(false);
}
}
Notes about why I used ConfigureAwait(false):
As a general rule, every piece of code that is not in a view model
and/or that does not need to go back on the main thread should use
ConfigureAwait false.
I'm creating an ASP layered web application and I have the following structure:
IService<T>
public interface IService<T> {
IEnumerable<T> GetAll();
void Add(T entity);
void Delete(T entity);
Service<T>
public class Service<T> where T : class {
private IRepository<T> _repository;
public Service(IRepository<T> repo) {
this._repository = repo;
}
public IEnumerable<T> GetAll() {
return _repository.GetAll();
}
etc
And then I also have some 'custom services':
ICategoryService
public interface ICategoryService : IService<Category> {
IEnumerable<Category> GetProductCategories(int productId);
}
CategoryService
public class CategoryService : Service<Category>, ICategoryService {
private IRepository<Category> _repository;
public CategoryService(IRepository<Category> repo) : base(repo) {
this._repository = repo;
}
public IEnumerable<Category> GetProductCategories(int productId) {
// implementation
}
Controller:
public class ProductController : Controller {
private ICategoryService _cservice;
public ProductController(ICategoryService cservice) {
this._cservice = cservice;
}
ยด
// other methods
public ActionResult Categories() {
IEnumerable<Category> categories = _cservice.GetAll(); // doesn't work
}
I'm trying to access the .GetAll() method in my controller, which was defined in IService and implemented in Service, but I'm getting a 'ICategoryService contains no definition for GetAll' error and I have no idea why.
I can access the .GetAll() method from my CategoryService, so I don't know why I can't access it from a CategoryService instance (via dependency injection).
You might have made a typo when posting your code, but, it seems that Service<T> doesn't implement IService<T> change the class's implementation to:
public class Service<T> : IService<T>
where T : class
{
private IRepository<T> _repository;
public Service(IRepository<T> repo) {
this._repository = repo;
}
public IEnumerable<T> GetAll() {
return _repository.GetAll();
}
I would also move the where T : class constraint from the class to interface.
I have two separate databases for storing documents and users. Also I've implemented generic repository pattern:
public class Repository<T> : IRepository<T> where T : class
{
public DbContext Context { get; set; }
public Repository()
{
}
public IEnumerable<T> Get(Expression<Func<T, bool>> expression)
{
return Context.Set<T>().Where(expression).AsEnumerable();
}
public void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public void Delete(T entity)
{
Context.Set<T>().Remove(entity);
}
public void Update(T entity)
{
Context.Set<T>().Attach(entity);
Context.Entry<T>(entity).State = EntityState.Modified;
}
public void SaveChanges()
{
Context.SaveChanges();
}
}
The problem is that entities are stored in different DbContexts and I can't use something like this:
container.Register(Component.For(typeof(IRepository<>)).ImplementedBy(typeof(Repository<>));
How can I specify which DbContext should be used for each entity?
For example, if I want create Repository that means that one database should be used, but if I want Repository another context should be used.
Or I should create two repo classes, like this:
public class AttachmetRepository<T> : IRepository<T> where T : class
{
public AttachmetsDbContext Context { get; set; }
...
}
public class UserRepository<T> : IRepository<T> where T : class
{
public UsersDbContext Context { get; set; }
...
}
The reason why I don't want to use two different repositories is to keep services simple, something like this:
public class SomeService: ISomeService
{
public IRepository<User> UserRepository { get; set; } //database 1
public IRepository<Comment> CommentsRepository { get; set; } //database 1
public IRepository<Attachment> AttachmentRepository { get; set; } //database 2
...
}
UPD:
As Ognyan suggested I've used FactoryMethod and this helped! Thanks a lot, Ognyan!
I'm new to CastleWindsor and I'm not sure its the best and fastest way, but here is my code:
public class EFDatabaseInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<AttContext>().LifeStyle.PerWebRequest);
container.Register(Component.For<DefContext>().LifeStyle.PerWebRequest);
container.Register(Component.For(typeof(IRepository<>)).UsingFactoryMethod((kernel, context) =>
{
var genericType = context.RequestedType.GetGenericArguments()[0];
Type type = typeof(Repository<>).MakeGenericType(genericType);
object repository = Activator.CreateInstance(type);
PropertyInfo dbContextProperty = type.GetProperty("Context");
if (genericType == typeof(Attachment))
{
dbContextProperty.SetValue(repository, kernel.Resolve<AttContext>());
}
else
{
dbContextProperty.SetValue(repository, kernel.Resolve<DefContext>());
}
return repository;
}).LifeStyle.PerWebRequest);
}
}
First you need not to hard code the DbContext inside the repository. You can remake your repository like this :
public class Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _dbContext;
// you can even make it IDbContextProvider with .Current() method in order not
// to place a hard dependency but depend on Interface which is the proper way.
// I was in a hurry and did not want to overcomplicate the implementation.
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
}
protected IDbSet<T> CreateSet<T>() where T : class
{
return _dbContext.Set<T>();
}
public virtual T Find(int id)
{
return CreateSet<T>().Find(id);
}
...
}
After that you need a factory method and a way to distinguish the destination db. One way to distinguish is to get the info from the CreationContext of the factory method :
private static DbContext DbContextFactoryMethod(IKernel k, ComponentModel cm, CreationContext c)
Here you can traverse the resolution stack and see if this is part of graph that contains IRepository or other entity and choose your database.
This way you will get the proper DbContext inside your repository without sticking all of them inside which will become more and more cumbersome with time.
I have written 3 repositories with the same format. How do I create a generic repository?
public class MyRepository : MyDataRepositoryBase<ASD>
{
protected override ASD AddEntity(MyDataContext entityContext, ASD entity)
{
return entityContext.ASDSet.Add(entity);
}
protected override IEnumerable<ASD> GetEntities(MyDataContext entityContext)
{
return from e in entityContext.ASDSet
select e;
}
}
This is where I am so far...
public class ComponentsRepository<T, U>:MyDataRepositoryBase<T>
where T : class,new()
where U : DbSet<U>, new()
{
protected override T AddEntity(MyDataContext entityContext, T entity)
{
return entityContext.U.Add(entity);
}
}
I am basically trying to find a way to call the DbSet "entityContext.ASDSet" without knowing what it is.
Any ideas or should I just let it go...
Entity Framework has a Set Method so you could do this
return entityContext.Set<T>().Add(entity);
But it won't check that you are passing in a class that isn't mapped. So it's use at your own risk, will throw an exception if it's not mapped. We have a base class that all our entity inherit from so we put a constraint on that, but even that there is no guarantee that a class is mapped in entity framework.
For what it's worth the generic repository is considered an anti-pattern. This is the implementation I used to use:
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext _context;
private readonly IDbSet<T> _dbSet;
public Repository(IDbContext context) {
_context = context;
_dbSet = context.Set<T>();
}
public void Add(T entity) {
_dbSet.Add(entity);
}
public void Update(T entity) {
_context.Entry(entity).State = EntityState.Modified;
}
...
}
My IDbContext:
public interface IDbContext
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry Entry<T>(T entity) where T : class;
int SaveChanges();
...
}
I used this with a UnitOfWork that I did my saving through and repository retrieval. That said, I really do find creating repositories around my entities a lot cleaner.
Im not sure if what I'd like to do is possible since I haven't found anything on google and after about 30minutes of intensive search I decided to ask directly.
I have definded a simple interface for my repository
public interface IRepository<TEntity> : IDisposable
{
TEntity GetById(object id);
List<TEntity> GetAll();
}
Now I want to implement my first repository and it works like this
public class ContentRepository : IRepository<ContentPages>
{
private readonly Context _db = new Context();
public ContentPages GetById(object id)
{
var result = _db.ContentPages.Find(id);
return result;
}
public List<ContentPages> GetAll()
{
return _db.ContentPages.ToList();
}
public void Dispose()
{
_db.Dispose();
}
}
This works fine but when I inject my repository to my mvc Controller it takes an IRepository<ContentPages> as parameter type and I just want it to take an IRepository.
I tried to move the generic type to the functions itself like this
public interface IRepository : IDisposable
{
TEntity GetById<TEntity>(object id);
List<TEntity> GetAll<TEntity>();
}
}
When I do this I don't know how to define my generic type TEntity in the implementation
So in conclusion I want my use the interface without speficing a type so it gets the type from the actual object like this
public constructor1(IRepository ContentRepository){}
the next controller gets this constructor
public constructor2(IRepository BlogRepository){}
and so on
I hope I could describe my problem close enough for u guys to understand :)
Within the concrete implementation of IRepository Class you can define the type of the TEntity as follows.
public TEntity GetById<TEntity>(object id) where TEntity:class
{
// Implimetation
}
But in here according to repository pattern better to use as follows.
public interface IRepository<TEntity>: IDisposable where TEntity : class
try such variant:
public interface IRepository<TEntity> where TEntity : class
{
TEntity Find(params object[] keyValues);
// ...
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly IDbSet<TEntity> _dbSet;
public Repository(IDbContext context)
{
_dbSet = context.Set<TEntity>();
}
public virtual TEntity Find(params object[] keyValues)
{
return _dbSet.Find(keyValues);
}
// ...
}
Example of usage:
IRepository<ApplicationUser> repository = new Repository<ApplicationUser>(new ApplicationDbContext());
ApplicationUser applicationUser = repository.Find("key");
Also, there is a better solution - you can use pattern UnitOfWork. Check this implementation on codeplex. It is really cool.
Example:
public class DatabasesController : Controller
{
private UnitOfWork _unitOfWork;
private WebContext _context;
public DatabasesController()
{
_context = new WebContext();
_unitOfWork = new UnitOfWork(_context);
}
//
// GET: /Databases/
public ViewResult Index()
{
List<Database> databases =
_unitOfWork
.Repository<Database>()
.Query()
.Include(database => database.FileEntitiesInfo)
.Get()
.ToList();
_unitOfWork.Save();
return View(databases);
}
}