I'm stuck in a decision that which one of these ways to use in my project.
Project is asp.net core mvc and layers are shown at this image(just to clear what i am looking for)
At first I used generic Repository Pattern for this project and codes are this
public interface IGenericRepository<TEntity> : IDisposable where TEntity:BaseModel
{
IQueryable<TEntity> GetEntitiesQuery();
Task<TEntity> GetEntityById(long entityId);
Task<TEntity> GetEntityByIdAsNoTracking(long entityId);
Task AddEntity(TEntity entity);
void UpdateEntity(TEntity entity);
void SoftRemoveEntity(TEntity entity);
Task SoftRemoveEntityById(long entityId);
void HardRemoveEntity(TEntity entity);
Task HardRemoveEntityById(long entityId);
Task SaveChangesAsync();
}
Its worked perfectly but I read that this generic repository pattern is old these days and also there is a problem when I want to use some entities in one service I have to inject each entity separately on my service which makes this harder on my test project.
Imagine this scenario that in my AccountService.cs on Register method I want to modify 4 entity User-Role-Log-Score so my constructor would be like this :
public class AccountService : IAccountService
{
private readonly IGenericRepository<User> _userRepository;
private readonly IGenericRepository<Role> _roleRepository;
private readonly IGenericRepository<Log> _logRepository;
private readonly IGenericRepository<Score> _scoreRepository;
public AccountService(IGenericRepository<User> userRepository, IGenericRepository<Role>
roleRepository, IGenericRepository<Log> logRepository, IGenericRepository<Score>
scoreRepository)
{
_userRepository = userRepository;
_roleRepository = roleRepository;
_logRepository = logRepository;
_scoreRepository = scoreRepository;
}
So this is huge and I do not think that is a good Idia to use something like this so I have 2 other options one is use DbContext directly without no Repositoy at all and one more way is using extension Methodes for DbContext like this
public static class DbContextExtension
{
public static IQueryable<TEntity> GetEntitiesQuery<TEntity>(this MainDbContext
dbContext) where TEntity : BaseModel
{
return dbContext.Set<TEntity>().AsQueryable();
}
public static async Task AddEntity<TEntity>(this MainDbContext dbContext, TEntity
entity) where TEntity : BaseModel
{
entity.CreateDate = DateTime.Now;
entity.LastUpdateDate = entity.CreateDate;
await dbContext.Set<TEntity>().AddAsync(entity);
}
}
If I use this way I only inject my dbContext once and I use every entity I want
So now Help me which way is better in performance and everything? which one do you suggest ? and why?
1: Generic Repository
2: DbContext Without Repository and unit of work
3: Extension Methode
Using IOC container to register all IRepositories as singletons,this is a good way to layer the modules. Each IPocoRepository should contain the common CURD APIs and it's unique business APIs.
PS: I don't like the generic solution.
Related
Im learning about generics and was wondering about how a generic controller, service and ef core repo design would look like.
My case: lets say an incomming post request to add Smartphone and keyboard object to smartphone and keyboard tables
My repository setup is
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class, IProductGenericEntities
{
private readonly MyDbContext _db;
public GenericRepository(MyDbContext db)
{
_db = db;
}
public async Task<bool> AddProduct(TEntity entity)
{
try
{
_db.Set<TEntity>().AddAsync(entity);
return (await _db.SaveChangesAsync()) > 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
}
And my service
public class ProductService<TEntity> : IProductService<TEntity>
where TEntity : class
{
private readonly IGenericRepository<TEntity> _repo;
public ProductService(IGenericRepository<TEntity> repo)
{
_repo = repo;
}
public async Task<bool> AddProduct(TEntity entity)
{
return await _repo.AddProduct(entity);
}
}
And my Controller.cs
[ApiController]
[Route("api/[controller]")]
public class ProductController
{
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
public ProductController(IProductService<Keyboards> keyService, IProductService<Smartphones> smartService)
{
_keyService = keyService;
_smartService = smartService;
}
[HttpPost("Post-generated-items")]
public async Task<ActionResult> PostProducts(List<TEntity> entities)
{
foreach(var item in entities)
{
and sort the objects here
}
}
}
is it correct to initialize 2 of IProductServices and sort the incomming objects to their correct DI on the controller?
private readonly IProductService<Keyboards> _keyService;
private readonly IProductService<Smartphones> _smartService;
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
Or is it what im doing plain wrong with a generic service layor?
Ok, so your approach is completely valid, i would not worry about initializing two repositories, since they're essentially empty memory vise since they just take reference to existant DbContext which by default is registered with Scoped lifecycle.
There will be a time when you need to use several repositories to complete task at hand. I would suggest going for NON-generic services approach. This way you could make ProductsService which has all the needed generic repositories injected and can orchestrate their work to achieve use case goal.
You might as well look into UOW (Unit Of Work) pattern for even more complex situations.
Answering your question:
Is there a way to make it more automatic by detecting incomming object type and then initilize it all the way to repo so i dont need 2 of IProductService<>?
You might write some code that would do just that for you using Reflection, but i would suggest against doing so. By initializing your repositories specifically you make yourself less error prone and code becomes more self-documenting.
For example now you have a controller that asks DI for two services and that instantly set's you up for what's going on in this controller. On the other hand if everything would be generic, you would end up with one huge knot of spaghetti that "Does everything".
Hello I use entity framework with a unit of work pattern and I would like to know if in my application layer I should work directly with entities generated by entity framework or recreate POCO objects in my application layer and map my POCO?
Because I would like my application layer not to make any reference to my entities, I would like for example to create another project in my solution that could map my entities to my poco in my application but I don't know if this is a good practice and especially I don't know how to do it
Thank you in advance!
In my UnitOfWork I have used a generic repository pattern that uses the models generated by the EF directly. The IRepository<T> interface looks a bit like this:
public interface IRepository<T> where T : class
{
void Add(T entity);
T GetById(long Id);
//etc - all the stuff you probably have
}
I have implementation of the IRepository called Repository
public Repository<T> : IRepository<T>
{
public readonly Infomaster _dbContext;
public Repository(Infomaster dbContext)
{
_dbContext = dbContext;
}
public void Add(T entity)
{
_dbContext.Set<T>.Add(t);
}
}
The use of the set and the type allows me to access the dataset (dbSet) of that particular type which allows me to create a generic pattern. You can use specific classes but it's a lot more work.
This means in my UnitOfWork, I only need to do the following:
public class UnitOfWork : IUnitOfWork
{
//Db context
Infomaster _dbContext;
//User is a model from my EF
public IRepository<User> UserRepository { get; private set; }
public UnitOfWork()
{
_dbContext = new Infomaster();
UserRepository = new Repository<User>(_dbContext);
}
public int Commit()
{
return _dbContext.Save();
}
}
I find that is the best way and requires the use of the model classes, I am using a code first database but I have done with database first.
(from iPhone - can and will update from laptop)
I am currently implementing EF6 to replace the ADO connection that currently exists.
I have read articles on why I should/shouldn't use the Repository pattern.
However I'm still not sure how to correctly call the repository pattern.
My project is layered as:
Presentation
Business Layer
Business Objects
Data Access Layer
Web Services
In the DAL I add my EF6 connection to my DB.
I created a IRepository and Repository classes.
Should the Business Layer be the one to call the Repository class?
If so I'm missing the connection here on how to call it.
Repository class:
public class MyRepository<T> : IRepository<T> where T : class
{
protected DbSet<T> DbSet;
protected DbContext _context;
public MyRepository(DbContext dataContext)
{
_context = dataContext;
DbSet = dataContext.Set<T>();
}
#region IRepository
public int Save()
{
return _context.SaveChanges();
}
public void Insert(T entity)
{
DbSet.Add(entity);
}
public void Delete(T entity)
{
DbSet.Remove(entity);
}
public IQueryable<T> SearchFor(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return DbSet.Where(predicate);
}
public IQueryable<T> GetAll()
{
return DbSet;
}
public T GetById(int id)
{
return DbSet.Find(id);
}
#endregion
}
My goal is to have MyRepository handle the 6 or so tables that I added in EF.
Where I am missing is how to implement this class in my business access layer.
I get the error
'MyEFConn' is a 'type' but is used like a 'variable'
My attempt at implementing it is:
MyRepository<"table from EF"> users = new MyRepository<"table from EF">(MyEFConn);
Which MyEFConn is my DbContext class..
public partial class MyEFConn: DbContext
I get the error 'MyEFConn' is a 'type' but is used like a 'variable'
This is because the constructor for MyRepository expects to be passed an instance of a DbContext. In your case that would be an instance of MyEFConn.
Ex:
MyEfConn context = new MyEfConn();
MyRepository<MyUsers> users = new MyRepository<MyUsers>(context);
I am working on ASP.NET MVC 4 project from scratch. I decided to start with the data access layer using Entity Framework 5 and Code First workflow. The company where I used to work was using very good implementation (in my opinion) of the Repository pattern including Repositories, Services, Abstract Factory for the Repositories and the Services and Unity for DI. I tried to redo it but it's just too complicated for me and will cost me a lot of time to replicate what I've been using there, so I decided to do some research and go with something lighter.
So I decided to use GenericRepository and UnitOfWork - far from what was the initial plan, but that was the implementation that was showing in most of my searches. So I did a very basic implementation (Just to the point where I'm sure I know what's going on, maybe even below my abilities to comprehend) and actually I think for this exact project it may be just enough but what I want is to be able to call additional custom methods on the different entities.
I think this gets a lot from the idea of generic repository, but if I try to go with some other implementation it's getting exponentially harder, so I wonder if there's a way to add this to my implementation without hurting too much the idea behind the generic Repository.
What I have now is the GenericRepository class :
public class GenericRepository<TEntity> where TEntity : class
{
internal DBContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DBContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToList();
}
//just the standard implementation
and my UnitOfWork class :
public class UnitOfWork : IDisposable
{
private DBContext context = new DBContext();
private CustomerRepository customerRepository;
public CustomerRepository CustomerRepository
{
get
{
if (this.customerRepository == null)
this.customerRepository = new CustomerRepository(context);
return customerRepository;
}
}
private GenericRepository<Order> orderRepository;
public GenericRepository<Order> orderRepository
{
get
{
So as you may see my Order entity is using the GenericRepository but I made a test class CustomerRepository to use for my Customer entity.
For now this class CustomerRepository looks like this :
public class CustomerRepository : GenericRepository<Customer>
{
public CustomerRepository(DBContext context) : base(context) { }
}
and the idea is to add the methods that are explicitly for the Customer entity here. I'm not sure if this is correct, especially the way I call the constructor. However, what is the natural way to add those specific methods for the different entities? I don't mind to even take a step back to implement it better but I don't want to rush it cause I tried and at the moment the whole concept is too complicated for me and I want to be sure that I understand the things that I use in my code.
I think you are on the right track. Here is the generic repository that I use:
public interface IRepository<TEntity>
where TEntity : class
{
IQueryable<TEntity> GetAll();
IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate);
TEntity GetById(long id);
void Add(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
}
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
protected readonly DbEntities Context;
protected readonly DbSet<TEntity> Set;
public Repository()
{
Context = new DbEntities();
Set = Context.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetAll()
{
return Set;
}
public virtual IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
{
return Set.Where(predicate);
}
public virtual TEntity GetById(long id)
{
return Set.Find(id);
}
public virtual void Add(TEntity entity)
{
Set.Add(entity);
Context.SaveChanges();
}
public virtual void Update(TEntity entity)
{
Set.Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
Context.SaveChanges();
}
public virtual void Delete(TEntity entity)
{
Set.Remove(entity);
Context.SaveChanges();
}
}
// And assuming User is a data object with an Id property:
public interface IUserSpecificRepository
{
List<User> GetById(long id)
}
public class UserSpecificRepository : IUserSpecificRepository, Repository<User>
{
public virtual List<User> GetById(long id)
{
return GetBy(x => x.Id = id).ToList();
}
}
Notice that GetAll() and GetBy() return a queryable. This is to allow control of when the query expression gets converted to SQL and hits the database. Usually a call to ToList() will cause this. You can then inherit from this and any custom methods can make use of these two starter methods.
Also, As a general rule of thumb, you should never do a GetAll().ToList() like you have now. If you have a zilion records you will run into problems. It is also a performance issue if you are filtering down to a few records. GetAll().ToList().Where(x => x.Id = 1) basically gets all zillion records from the db into memory, then filters it down to one. You should instead do this GetAll().Where(x => x.Id = 1).ToList().
Hope this helps you along!
I'm gonna to use repository and UnitOfwork in my data access layer to do this take a look at one contact aggregateroot
public interface IAggregateRoot
{
}
this is my Generic repository interface :
public interface IRepository<T>
{
IEnumerable<T> GetAll();
T FindBy(params Object[] keyValues);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
and my POCO Contact class in Model
public class Contact :IAggregateRoot
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public DateTime CreationTime { get; set; }
}
and this my IContactRepository that inherit from IRepository and also maybe has it is own method
public interface IContactRepository : IRepository<Contact>
{
}
Now I have done in IUitOfWork and UnitOfwork like this
public interface IUnitOfWork
{
IRepository<Contact> ContactRepository { get; }
}
public class UnitOfWork : IUnitOfWork
{
private readonly StatosContext _statosContext = new StatosContext();
private IRepository<Contact> _contactUsRepository;
public IRepository<Contact> ContactRepository
{
get { return _contactUsRepository ?? (_contactUsRepository = new Repository<Contact>(_statosContext)); }
}
}
also about my Repository
public class Repository<T> : IRepository<T> where T : class, IAggregateRoot
{
//implementing methods
}
I can do all CRUD operation with accessing Repositories with UnitOfwork in Service , example :
_unitOfWork.ContactRepository.Add(contact);
_unitOfWork.SaveChanges();
but I want to do like this
_
ContactRepository.Add(contact);
_unitOfWork.SaveChanges();
(get CRUD and generic method via _ContactRepository No by _unitOfWork.ContactRepository)
Because I want to get ContactRepository method to some specific queries ,
anybody help please ??
It's not a direct answer to your question, but it might simplify things a little bit and reduce duplication.
When you use e.g. EntityFramework Power Tools to reverse-engineer Code First (or just use Code First in general), you end up with the DbContext class that serves as a UoW and repository in one, e.g.:
public partial class YourDbContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
Now, if you want things to be testable, there's an easy way: introduce a very thin interface:
public interface IDbContext
{
IDbSet<T> EntitySet<T>() where T : class;
int SaveChanges();
//you can reveal more methods from the original DbContext, like `GetValidationErrors` method or whatever you really need.
}
then make another file with second part of the partial class:
public partial class YourDbContext : IDbContext
{
public IDbSet<T> EntitySet<T>() where T : class
{
return Set<T>();
}
}
Ta-da! Now you can inject IDbContext with YourDbContext backing it up:
//context is an injected IDbContext:
var contact = context.EntitySet<Contact>().Single(x => x.Id == 2);
contact.Name = "Updated name";
context.EntitySet<Contact>().Add(new Contact { Name = "Brand new" });
context.SaveChanges();
Now if you want to have control over the disposal of the context, then you'd have to write your own (gasp) IDbContextFactory (generic or not, depending what you need) and inject that factory instead.
No need to write your own Find, Add or Update methods now, DbContext will handle that appropriately, it's easier to introduce explicit transactions and everything is nicely hidden behind interfaces (IDbContext, IDbSet).
By the way, the IDbContextFactory would be an equivalent to NHibernate's ISessionFactory and IDbContext - ISession. I wish EF had this out of the box, too.
I agree with the Doctor, DbContext is already a UnitOfWork, and adding another UoW abstraction on top of it is typically redundant, unless you think it's highly likely you might switch database technologies in the future.
I don't agree, however, with treating DbSet's as repositories, since this tightly couples your queries to the methods that use them. If you need to change a query, you have to do it everywhere you use it.
I prefer to either use a stand-alone repository (or service interface, they serve similar functions) or to use more of a CQRS system for Command/Query Seperation, an use query objects.
Inside the UnitOfWork class you need to implement DBContext or ObjectContext.
UnitOfWork segregates all transactions regardless of the system. EF is only for DB connection. Even if your system is only using DB still it is better to keep a separate UnitOfWork class for future expansions.
And inside the unit of work Commit(), you can call the internally implemented DBContext.SaveChanges().
This DBcontext will be accessible to all repositories declared inside unitofwork. So repositories add or delete from DBcontext and unitOfwork commits it.
When you have scenarios spanning different storages eg: Cloud Blobs, table storage etc. You could implement them inside UnitofWork just like you implemented a EF context. And some repositories can access Table Storage and some EF context.
Tip: Implementing ObjectContext instead of DBContext gives you an edge in caching scenarios. And you have more options in extending your framework.