I have been looking at the decorator design pattern (I am new to the subject of design patterns).
I am already using BaseRepository pattern. But I want to use some cache too.
Below sample is just a dump example.
So I have IGenericRepository interface and the implementation to it.
public interface IGenericRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> GetAll();
Task<T> GetByIdAsync(int id);
T Add(T entity);
void AddRange(IEnumerable<T> entities);
Task<T> AddAsync(T entity);
Task AddRangeAsync(IEnumerable<T> entities);
void Remove(T entity);
void RemoveRange(IEnumerable<T> entities);
int SaveChanges();
Task<int> SaveChangesAsync();
}
Then I created a custom repository for example IBlogRepository
public interface IBlogRepository : IBaseRepository<Blog>
{
public Task<Blog> GetBlogsByCreatorAsync(int creatorId);
}
With the implemantation of BlogRepository
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId) =>
db.Blogs.Where(b => b.CreatorId == creatorId)
.ToListAsync();
}
I thought this is cool, then I realised I need to improve my "speed". I am starting use IMemoryCache, but in Repository code like below.
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db, IMemoryCache cache) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId)
{
// if in cache else go to db
}
}
Then I met with Decorate pattern and I thought why not, I started to use it, but I am struggling now. I created CachedBlogRepository which is implement IBlogRepository, but when I asked to VS implement all interface method...
public class CachedBlogRepository : IBlogRepository
{
//All BaseRepository methods appeared here...
//But I want cache only the GetBlogsByCreatorAsync method
}
So what is the best practice here? Do I missing something or did I something wrong?
It looks like it is a place where CachedRepository pattern can be used.
I highly recommend you to read this beatuiful article about Building a CachedRepository in ASPNET Core
So after applying CachedRepository pattern would look like this:
public List<Blog> GetBlogsByCreatorAsync(int id)
{
string key = MyModelCacheKey + "-" + id;
return _cache.GetOrCreate(key, entry =>
{
entry.SetOptions(cacheOptions);
return _repository.GetBlogsByCreatorAsync(id);
});
}
You can see source code at gihub
First I don't understand this part:
BlogRepository : BaseRepository, IBlogRepository
shouldn't it be just:
BlogRepository : IBlogRepository?
Now when it comes for the Decorator Pattern I would have done this:
public interface IGenericRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> GetAll();
Task<T> GetByIdAsync(int id);
T Add(T entity);
void AddRange(IEnumerable<T> entities);
Task<T> AddAsync(T entity);
Task AddRangeAsync(IEnumerable<T> entities);
void Remove(T entity);
void RemoveRange(IEnumerable<T> entities);
int SaveChanges();
Task<int> SaveChangesAsync()
}
(Component)
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId) =>
db.Blogs.Where(b => b.CreatorId == creatorId)
.ToListAsync();
}
(Concrete Component)
abstract class Decorator : IGenericRepository<T>
{
protected IGenerecRepository _repository;
public Decorator( IGenerecRepository repository)
{
this._repository = repository;
}
public override Task<Blog> GetBlogsByCreatorAsync()
{
if (this._repository != null)
{
return this._repository.GetBlogsByCreatorAsync();
}
else
{
return string.Empty;
}
}
}
(Base Decorator)
class CacheDecorator : Decorator
{
public CacheDecorator(IGenericRepository repo) : base(repo)
{
}
public override Task<Blog> GetBlogsByCreatorAsync()
{
//cache behavior
}
}
Uasage:
BlogRepository _basicRepo = new BlogRepository();
CacheDecorator _cacheDecorator = new CacheDecorator(_basicRepo);
_cacheDecorator.GetBlogsByCreatorAsync(creatorId);
Decorator Pattern adds behavior to the main basic behavior. It needs a wrappee (the basic component) to wrap new behavior around it.
Related
I'm trying to implement a repository in my project and I'm following this post https://stackoverflow.com/a/4535781/10419620.
Here's the code:
The interface:
namespace FolhaRegisto.Database.Repositories
{
public interface IRepository<TEntity>
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
}
and the class
namespace FolhaRegisto.Database.Repositories
{
public class Repository<T> : IRepository<T> where T : class
{
DataContext db;
public Repository(DataContext db)
{
this.db = db;
}
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
db.SubmitChanges();
}
}
}
I can't find anything explicit for Web Forms. I think I understand how it works but I still don't know how do i provide a connection string to the DataContext. I created a Linq to SQL class and selected tables, but I don't know what to do next.
for whoever feels lost in this topic like me. I think what you are looking for is Model-Binding in Webforms.
Here's the tutorial I managed to find that explains clearly everything in detail.
https://learn.microsoft.com/en-us/aspnet/web-forms/overview/presenting-and-managing-data/model-binding/retrieving-data
Very good!
I am trying to implement UOW with repository pattern in my application.
While the independent repository is in place, but while multiple repositories in one transaction (UOW) is driving me crazy.
EF Relation One Customer - Many CustomerContacts
IUnitOfWork
public interface IUnitOfWork
: IDisposable
{
void InitTransaction();
void Rollback();
void CommitTransaction();
}
BaseUOW
public class UnitOfWork :
IUnitOfWork
{
protected DbContextTransaction _transaction;
#region IUnitOfWork
public void CommitTransaction()
{
_transaction.UnderlyingTransaction.Commit();
}
public void Rollback()
{
_transaction.UnderlyingTransaction.Rollback();
}
#endregion IUnitOfWork
}
CustomerUOW
public class CustomerUOW
: UnitOfWork
{
private IRepository<CustomerRepository> _customerRepository;
private IRepository<CustomerContactRepository> _customerContactRepository;
public BranchUOW(IRepository<CustomerRepository> customerRepository,
IRepository<CustomerContactRepository> customerContactRepository)
{
_customerRepository= customerRepository;
_customerContactRepository= customerContactRepository;
}
public override void InitTransaction()
{
_transaction.Commit();
}
}
How do I implement my CustomerUOW so that Customer &
CustomerContact repository share the same DbContext & goes in one
transaction??
Note: Each repository has an implementation of CRUD in their separate class. like
public class EntityRepository<C, T>
: BaseRepository<FoodieTenantContext, T>
where T : class
where C : CustomerContext
{
private DbSet<T> _dataSet
{
get
{
return _ctx.Set<T>();
}
}
public EntityRepository(FoodieTenantContext ctx)
: base(ctx)
{
}
public override void Add(T entity)
{
_dataSet.Add(entity);
}
public override void Delete(T entity)
{
throw new NotImplementedException();
}
public override IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).ToList<T>();
}
public override IEnumerable<T> GetAll()
{
return _dataSet.ToList<T>();
}
public override IQueryable<T> GetQuery()
{
return _dataSet;
}
public override int Save()
{
return _ctx.SaveChanges();
}
public override T Single(Expression<Func<T, bool>> predicate)
{
return _dataSet.Where(predicate).SingleOrDefault();
}
public override void Update(T entity)
{
_dataSet.Attach(entity);
_ctx.Entry<T>(entity).State = EntityState.Modified;
}
}
Thanks
On way would be to provide a Func<FoodieTenantContext, IRepository<CustomerContactRepository>> in your CustomerUow
public abstract class UnitOfWork : IUnitOfWork
{
public UnitOfWork(FoodieTenantContext context)
{
this.Context = context;
}
// ... rest of the class
}
// usage could be like the following
public class CustomerUOW : UnitOfWork
{
public CustomerService(Func<FoodieTenantContext, IRepository<CustomerRepository>> customerRepo
, Func<FoodieTenantContext, IRepository<CustomerContactRepository>> contactRepo
, FoodieTenantContext context)
: (context)
{
_customerRepo = customerRepo(context);
_contactRepo = contactRepo(context);
}
}
Another option would be to create a RepositoryFactory, but this would mean you would have to expose a Context property from IRepository<T>
public class RepositoryFactory
{
IServiceProvider _ioc; // This would be your IoC/DI Container
public RepositoryFactory(IServiceProvider ioc)
{
_ioc = ioc;
}
// Resolve T passing in the provided `FoodieTenantContext` into the constructor
public IRepository<T> CreateRepository<T>(FoodieTenantContext context) =>
_ioc.Resolve<T>(context);
}
Another solution could be (my least favourite) would be to expose methods in a RepositoryFactory for each type of IRepository<T>
public class RepositoryFactory
{
public IRepository CreateCustomerContactRepository(FoodieTenantContext context) =>
return new CustomerContactRepository(context);
}
Registering Func in Castle.Windsor
As per comment, to register Func<T> in Castle.Windsor you can try something like the following which is a modified version of Anton's answer to Func injecting with Windsor container question.. (I am not able to test this right now)
Container.Register(
Component.For<Func<FoodieTenantContext, IRepository<CustomerRepository>>>()
.Instance((FoodieTenantContext context) => Container.Resolve<IRepository<CustomerRepository>>(new {context = context}))
)
Otherwise you could try playing around with AsFactory(). For more info read Windsor documentation
And as a last resort, you can always fallback to manually creating a factory or switching IoC/DI containers that support Func<[TIn1, TIn2, ...], T> out of the box, or at least natively.
I am moving from inheritance to compositon, as you can see from here https://stackoverflow.com/questions/29653153/composition-migrating-from-inheritance
Now i have got it all working, but simple injector wants me to manually register each interface with each type being passed in. Here is the striped down code.
I have IBaseEntityService, which BaseEntityService implements, like so
public interface IEntityBaseService<T> where T : class, IEntityBase
{
IDataContext Context { get; }
Task<ICollection<T>> GetAllAsync();
Task<T> GetAsync(long id);
}
public class EntityBaseService<T> : IEntityBaseService<T>
where T : class, IEntityBase
{
protected IDataContext _context;
public IDataContext Context
{
get
{
return _context;
}
}
public EntityBaseService(IDataContext context)
{
_context = context;
}
public async Task<ICollection<T>> GetAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public Task<T> GetAsync(long id)
{
return _context.Set<T>().Where(e => e.Id == id).FirstOrDefaultAsync();
}
}
Now i have a IValidationService and ValidationService implements that, like so
public interface IValidationService<T>
where T : class, IEntityBase
{
Task<ValidationResult> ValidateAsync(T entity);
Task<int> AddAsync(T entity);
Task<int> UpdateAsync(T entity);
}
public class ValidationService<T> : IValidationService<T>
where T : class, IEntityBase
{
private IEntityBaseService<T> _service;
private IValidator<T> _validator = null;
public IDataContext Context
{
get
{
return _service.Context;
}
}
public ValidationService(IEntityBaseService<T> service, IValidator<T> validator)
{
_service = service;
_validator = validator;
}
public Task<ValidationResult> ValidateAsync(T entity)
{
if (_validator == null) throw new MissingFieldException("Validator does not exist for class " + entity.GetType().ToString() + ". override method if no validation needed");
return _validator.ValidateAsync(entity);
}
public async Task<int> AddAsync(T entity)
{
var results = await ValidateAsync(entity);
if (!results.IsValid)
{
throw new ValidationException(results.Errors);
}
return await _service.AddAsync(entity);
}
public async Task<int> UpdateAsync(T entity)
{
var results = await ValidateAsync(entity);
if (!results.IsValid)
{
throw new ValidationException(results.Errors);
}
return await _service.UpdateAsync(entity);
}
}
Now i can use services, and pass in each interface. So i have a IContentService and ContentService which implements that. This service uses both IEntityBaseService and IValidationService
public interface IContentService
{
Task<Content> GetAsync(long id);
Task<int> AddAsync(Content entity);
Task<int> UpdateAsync(Content entity);
}
public class ContentService : IContentService
{
private IEntityBaseService<Content> _service;
private IValidationService<Content> _validation;
public ContentService(IEntityBaseService<Content> service, IValidationService<Content> validation)
{
_service = service;
_validation = validation;
}
public async Task<Content> GetAsync(long id)
{
var content = await _service.Context.Contents
.Where(e => e.Id == id)
.WhereNotDeleted()
.FirstOrDefaultAsync();
if (content != null)
{
content.Attachments = await _service.Context.Attachments
.Where(e => e.ContentId == id)
.WhereNotDeleted()
.ToListAsync();
}
return content;
}
public Task<int> AddAsync(Content entity)
{
return _validation.AddAsync(entity);
}
public Task<int> UpdateAsync(Content entity)
{
return _validation.UpdateAsync(entity);
}
}
Now in my config file, i have this, which works, but if i have another service, and i have about 20 of them, i do not want to type this out for each one.
container.Register<IEntityBaseService<Content>, EntityBaseService<Content>>();
container.Register<IValidationService<Content>, ValidationService<Content>>();
container.Register<IValidator<Content>, ContentValidator>();
container.Register<IContentService, ContentService>();
So i looked online and i think i can use the RegisterManyForOpenGeneric method instead of registering IEntityBaseService and IValidatioNService, but i cannot get it too work. I have wrote
container.RegisterManyForOpenGeneric(typeof(IEntityBaseService<>), typeof(IEntityBaseService<>).Assembly);
container.RegisterManyForOpenGeneric(typeof(IValidationService<>), typeof(IValidationService<>).Assembly);
And i get an error saying
The constructor of type ContentService contains the parameter of type
IEntityBaseService with name 'service' that is not
registered. Please ensure IEntityBaseService is registered in
the container, or change the constructor of ContentService.
Maybe i have set up my entities incorrectly, so just encase, here are the basic entities for this example
public interface IEntityBase
{
long Id { get; set; }
}
public abstract class EntityBase : IEntityBase
{
public long Id { get; set; }
}
public class Content : EntityBase, IAudit
{
public short Position { get; set; }
public Content()
{
Position = 1;
}
}
Any help much appreciated on both simple injector and the code in general
You're using the wrong registration method.
RegisterManyForOpenGeneric exists to support the following scenario:-
container.Register<IValidate<Customer>, CustomerValidator>();
container.Register<IValidate<Employee>, EmployeeValidator>();
container.Register<IValidate<Order>, OrderValidator>();
container.Register<IValidate<Product>, ProductValidator>();
// can replace the above with the following:-
container.RegisterManyForOpenGeneric(
typeof(IValidate<>),
typeof(IValidate<>).Assembly);
By default RegisterManyForOpenGeneric searches the supplied assembly for all types that implement the [specified open generic] interface and registers each type by their specific (closed generic) interface. [Emphasis mine]
Note how the concrete types aren't themselves generic (i.e. CustomerValidator implements the closed generic interface IValidate<Customer>). This works fine for your ContentValidator but is no good for open generic classes implementing open generic interfaces like your EntityBaseService<Content> and ValidationService<Content>.
You're looking for:-
container.RegisterOpenGeneric(
typeof(IEntityBaseService<>),
typeof(EntityBaseService<>));
RegisterManyForOpenGeneric has been marked obsolete now.
container.Register(typeof(IValidator<>), new[] { typeof(IValidator<>).Assembly });
Is the way to go now.
http://simpleinjector.readthedocs.org/en/latest/advanced.html
I have a generic Repository like this:
public interface IRepository<TEntity> where TEntity :class
{
IEnumerable<TEntity> SearchFor(Expression<Func<TEntity, bool>> filter);
TEntity GetById(int id);
void Insert(TEntity entity);
void Delete(TEntity entity);
void Update(TEntity entity);
}
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity: class
{
private DbSet<TEntity> _dbSet; // put the entity specified in place of TEntity in d DbSet so i can query the entity e.g School Entity
private NaijaSchoolsContext _naijaSchoolsContext;
public GenericRepository(NaijaSchoolsContext context)
{
_naijaSchoolsContext = context;
_dbSet = _naijaSchoolsContext.Set<TEntity>(); //return the entity specified in the TEntity and put it in DbSet
}
public IEnumerable<TEntity> SearchFor(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter)
{
return _dbSet.Where(filter);
}
public TEntity GetById(int id)
{
return _dbSet.Find(id);
}
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
}
public void Delete(TEntity entity)
{
_dbSet.Remove(entity);
}
public void Update(TEntity entity)
{
_dbSet.AddOrUpdate(entity);
}
}
I also have a UoW like this:
public interface IUnitofWork : IDisposable
{
void Save();
}
public class UnitofWork : IUnitofWork
{
NaijaSchoolsContext naijaSchoolsContext = new NaijaSchoolsContext();
private GenericRepository<School> schoolRepository;
private bool isDisposed = false;
public GenericRepository<School> SchoolRepository
{
get
{
if (schoolRepository == null)
{
schoolRepository = new GenericRepository<School>(naijaSchoolsContext);
}
return schoolRepository;
}
}
public void Save()
{
naijaSchoolsContext.SaveChanges();
}
public void Dispose(bool disposing)
{
if (!isDisposed)
{
if (disposing)
{
naijaSchoolsContext.Dispose();
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
My test class looks like this:
[TestFixture]
public class when_working_with_school_repository
{
}
public class and_saving_a_school : when_working_with_school_repository
{
private School _returnedSchool;
private School _school;
private Mock<IRepository<School>> _repository;
private Exception _result;
[SetUp]
private void SetUp()
{
_repository = new Mock<IRepository<School>>();
_school = new School();
}
[Test]
public void then_a_valid_school_should_be_saved()
{
_repository.Setup(s => s.Insert(_school));
//_returnedSchool = _schoolRepository.Save(_school);
}
[Test]
public void should_throw_an_exception_when_no_school_is_saved()
{
try
{
_repository.Setup(s => s.Insert(null));
}
catch (Exception exception)
{
_result = exception;
}
}
[Test]
public void should_notify_user_if_school_name_already_exists()
{
//bool exists = _schoolRepository.IsExist(_school.Name);
}
}
My tests passes but my concern is that
Am I not supposed to mock the UnitOfWork class. When I tried mocking it, i couldn't get to the StudentRepository class. In using the code without tests, I would have to instantiate UoW to perform my actions, that is why i asked if am supposed to Mock my UoW. if am to Mock it how can i do that?
Please help me if my test is correct or I need to take another course of action.
No, you are not. You are testing mock:
_repository = new Mock<IRepository<School>>();
You want to test your code, not others. Your generic repository simply delegates calls to _dbSet. And that's what you want to test - that calls are delegated (this is sort of wrapper-functionality).
How to do that? You need abstraction over DbSet<T> and this is the object you mock in test. All your tests will look similar:
var dbSetMock = new Mock<DbSet<School>>();
var context = new Mock<Context>();
var repository = new GenericRepository<School>(dbSetMock, context);
repository.FindBy(arg);
dbSetMock.Verify(d => d.FindBy(arg));
This requires abstraction over both DbSet and your custom context to make it work.
I think you're better of mocking the IRepository. But, your test will pass because your not asserting for anything.
I think you need to setup your your mock inorder to get the desired result. Here is a modified example:
[Test]
public void then_a_valid_school_should_be_saved()
{
var _school = new School { .... };
var expected = _school.Id;
_repository.Setup(s => s.Insert(_school));
_repository.Setup(s => s.GetById(_school.Id)).Returns(_school);;
_repository.Insert(_school);
var actual = _repository.GetById(_school.Id);
Assert.Equal(expected, actual);
}
That should do it. To make the test fail try putting a different Id for the expected result and verify that it works. You can use that to improve upon your other test.
I m working with an application in which Base inteface has been created as below
public interface IBaseRepository : IDisposable
{
bool IsUnitOfWork { get; set; }
void SaveChanges();
}
Then other interfaces extend this interface as
public interface ICourseRepository : IBaseRepository
{
Course GetCourseById(int id);
List<Course> GetCourses();
CourseModule GetCourseModuleById(int id);
}
Just wondering what would be the advantage of this approach
The base repository allows you to specify behavior you want all repository contracts to have without repeating it in every IMyEntityRepository you create.
Even more fun though is then implementing a Base Repository like this and specifying generic code for generic operations:
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class {
private DbContext _context;
public Repository(DbContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
_context = context;
}
protected DbContext DbContext { get { return _context; } }
public void Create(TEntity entity) {
if (entity == null) {
throw new ArgumentNullException("entity");
}
DbContext.Set<TEntity>().Add(entity);
DbContext.SaveChanges();
}
public TEntity GetById(int id) {
return DbContext.Set<TEntity>().Find(id);
}
public void Delete(TEntity entity) {
if (entity == null) {
throw new ArgumentNullException("entity");
}
DbContext.Set<TEntity>().Attach(entity);
DbContext.Set<TEntity>().Remove(entity);
DbContext.SaveChanges();
}
public void Update(TEntity entity) {
if (entity == null) {
throw new ArgumentNullException("entity");
}
DbContext.Set<TEntity>().Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
DbContext.SaveChanges();
}
etc., Then have your MyEntityReporitory extend your BaseRepository
You can reuse the base interface for multiple classes/interfaces without requiring implementation of other interfaces also - so you can have IsUnitOfWork available on a bunch of classes, without needing to also implement GetCourseById on all of those classes. However you can also ensure that all CourseRepositories are treated as units of work.