GenericRepository and UnitOfWork customization - c#

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!

Related

Which lifetime-manager do I register my DbContext into Unity container when writing a WPF application?

I am writing a new C# application on the top of Prism 6.3 framework using the well-known MVVM design pattern. I am using Unity IoC container to help me manage my dependencies.
I am using Entity Framework Core to interact with the database. However, I don't want to tightly couple my application to Entity Framework Core, so I implemented Repository and UnitOfWork patterns to make it easy for me to swap out the Entity Framework Core implementation if needed.
My repository implementation provides a method called Save() which calls EF Core's SaveChanges() method. The repositories are injected into my business-service so that my business-service expose one method to do a single task. For example, if I want to create a new order, I would call the Create(orderViewModel) method which internally calls the Add() and the Save() method on the OrderRepository.
Additionally, the UnitOfWork provides Save(), BeginTransaction(), Commit() and Rollback() methods which allow me control the transaction behavior. In another words it will give me the flexibility to either commit or rollback the SQL transaction when needed.
To explain my use case better, here is an example of how I would add new order to my database directly using the business-service without transaction or unit-of-work.
OrdersService.Create(orderViewModel); // this will call the `Add` and the `Save()` methods on the OrderRepository;
Here is another example which demonstrate how I would add a new order and order-items to my database using the business-services while using unit-of-work to start transaction and control the transaction.
using(var transaction = UnitOfWork.BeginTransaction())
{
try
{
var order = OrdersService.Create(orderViewModel);
OrdersService.CreateRange(order.Id, orderItemsViewModel);
transaction.Commit();
}
catch(Exception e)
{
Log.Add(e);
transaction.RollBack();
}
}
In the second example above, even-though the OrdersService.Save and OrdersService.SaveRange each call the SaveChanges() method the data are not committed to the database since I am wrapping them with a transaction.
Question: what LifeTimeManager should I register the DbContext, IUnitOfWork and each of my repositories with?
In a web environment, I would register everything using PerRequestLifetimeManager then during the request I am reusing the same DbContext and everything works fine and the DbContext is disposed at the end of the http request. But not sure how to register everything in a WPF application where I can still use transaction to control everything while allowing the repository to call the SaveChanges()
If needed here is my EntityRepository implementation
public class EntityRepository<TEntity, TKeyType> : IRepository<TEntity, TKeyType>
where TEntity : class
where TKeyType : struct
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(TKeyType id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public bool Any(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Any(predicate);
}
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public virtual TEntity Add(TEntity entity)
{
var record = Context.Add(entity);
record.State = EntityState.Added;
return entity;
}
public virtual IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
{
Context.AddRange(entities);
return entities;
}
public void Remove(TEntity entity)
{
Context.Remove(entity).State = EntityState.Deleted;
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
Context.RemoveRange(entities);
}
public void Update(TEntity entity)
{
DbSet.Attach(entity);
var record = Context.Entry(entity);
record.State = EntityState.Modified;
}
public IQueryable<TEntity> Query()
{
return DbSet;
}
public void Save()
{
Context.SaveChanges();
}
}
And here is my unit of work implementation
public sealed class UnitOfWork : IUnitOfWork
{
private bool IsDisposed = false;
private readonly DbContext Context;
public IOrderRepository Orders { get; private set; }
public IOrderItemRepository OrderItems { get; private set; }
public UnitOfWork(DbContext context)
{
Context = context;
Orders = new OrderRepository(context);
OrderItems = new OrderItemRepository(context);
}
public int Save()
{
Context.SaveChanges();
return 0;
}
public void Dispose()
{
Dispose(true);
}
public IDatabaseTransaction BeginTransaction()
{
return new EntityDatabaseTransaction(Context);
}
private void Dispose(bool disposing)
{
if (IsDisposed)
{
return;
}
if (disposing)
{
Context.Dispose();
}
IsDisposed = true;
}
}
Transient (an instance per view) lifetime would be the way to go if your DI doesn't support scoping, but then you would need to abstract away your DbContext being passed through into the repo's and unitOfWork, otherwise new instances of the DbContext will be passed in there. On construction of the page, a new instance is created, and on moving away from that view, that DBContext should be disposed of. UnitOfWork would follow the same path as you wouldn't want a UnitOfWork spanning multiple instances of a DBContext.
See http://blogs.microsoft.co.il/gilf/2010/02/07/entity-framework-context-lifetime-best-practices/. Otherwise, if your DI has the concept of container hierarchies, and you're able to create a container scope per view, then a singleton would work in this instance and you wouldn't need any abstractions mentioned above and would be quite a bit easier to work with.

Where to put DSet DataAccess logic using Entity Framework?

I'm using CodeFirst EF6 and I'd like to place all related "queries" into a single class.
Let's say I have a
DbSet<Car> Cars;
in my DbContext.
I tried to create a new class with my concrete DbSet as base class:
public class CarRepository : DbSet<Car>
in which I'd locate all car related operations.
When I replace DbSet with CarRepository in my DbContext class it won't get filled.
I then tried to derive from IDbSet but I'm not sure how to implement all needed methods.
Is there another way to achieve this goal without using an extension class?
You can simply create your own single class(your repository) and put your methods like this.
public class Repository<TEntity> where TEntity : class
{
private DbContext context;
private DbSet<TEntity> dbSet;
public Repository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
}

Trying to understand Repository Pattern with EF6

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);

Single Query to retrive records from more than one repository

Can Please sugget Best /Efficient way to perform CRUD Opration in MVC application.
I am using Entity Framework in my project for Database access.
ex: EDMX: SupportContext ;
Here i performed the CRUD Operation using SupportContext [.edmx}. which processed more quickly than repository. and also i can retrive data's from more than one context object[table's] in a LinQ query.
ex:
using (SupportContext support =new SupportContext())
{
var=(from t1 in support.table1
from t2 in support.table 2
where t1.id==t2.id
select t1).ToList();
}
I have used Generic Repository Pattern for instead of direct access with EDMx. it act layer between my code logic and EDMX file. find the generic example.
code:
public interface IRepository<T> : IDisposable where T : class
{
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T entity);
void SaveChanges();
}
public class GenericRepository<T> : IRepository<T> where T : class
{
private ObjectContext _context;
private IObjectSet<T> _objectSet;
public GenericRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _objectSet.Where<T>(predicate);
}
public void Add(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.AddObject(entity);
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
Here i have used this repository for CRUD opration as:
var dat1=new GenericRepository<Table1>(new SupportContext());
var dat2=new GenericRepository<Table2>(new SupportContext());
Here i want to retrieve the records in both dat1,dat2 repository while it Id filed is equal. But I can't able to retrieve in combine way. but do it in single way.
var=dat1.Find(t=>t.id==3).toList();
Can you please suggest how to retrieve data 's from combined repository AND also suggest which method is best way to Access data ?

How to test MVC actions with Code First?

I'm trying to test MVC actions, so i created IRepository and MockRepository
public class Repository : DbContext, IRepository
{
public IDbSet<TEntity> SomeEntities { get; set; }
}
public interface IRepository : IDisposable
{
IDbSet<TEntity> SomeEntities { get; set; }
int SaveChanges();
}
With Create and Delete actions it was simple, but stuck with Edit action :
private IRepository repository;
public ActionResult Edit(TEntity entity)
{
if (ModelState.IsValid)
{
repository.Entry(entity).State = EntityState.Modified;
repository.SaveChanges();
return RedirectToAction("Index");
}
return View(entity);
}
So i see two ways to solve this problem:
should i add to IRepository new method
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
How i could do this? DbContext.Entry method returns very specific DbEntityEntry<TEntity> type?
or change the way i update entity? What is recommended way to do this?
I would normally abstract the functionality of EF more than you are, meaning my actions look the following.
private IRepository repository;
public ActionResult Edit(TEntity entity)
{
if (ModelState.IsValid)
{
repository.Update(entity);
repository.SaveChanges();
return RedirectToAction("Index");
}
return View(entity);
}
then you can easily make a mock repository and test that the desired functions are called.
Note: I normally also separate my entities from my models and manage my unit of work using an action filter, but that's not really related to this post.

Categories

Resources