In my project, I'm using EF Code First approach following Code Camper structure. So i have generic repository IRepository;
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
and then it's implementation EFRepository<T>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}
protected DbContext DbContext { get; set; }
protected DbSet<T> DbSet { get; set; }
public virtual IQueryable<T> GetAll()
{
return DbSet;
}
public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}
Based on customer needs, i should not delete any DB records, so for most(not all of them) tables I have isDeleted property to mark record as deleted. And these records which marked as isDeleted should not appear to users
My question is: How in my generic repository implementation check for that isDeleted property while I'm expecting generic object T.
For example GetAll function should be:
public virtual IQueryable<T> GetAll()
{
return DbSet.where(x=>x.isDelete == false);
}
Any ideas, how i can do that?
Create an interface with IsDeleted property and inherit all your models from it. Then you could modify your repository like this:
public class EFRepository<T> : IRepository<T> where T : TypeOfYourNewInterface
Now you can access IsDeleted in generic methods.
I could not find a suitable solution to my problem. After more searching i ended with 3 solutions:
Create extension methods.
Create a custom IDbSet which can accept a filter expression.
Add a discriminator to every model.
I choosed solution(3) although, I don't like it much
Related
We are using entity framework with repository/unit of work pattern. Now, we would like to use dapper along with EF. Below are few basic classes we are using:
public interface IRepository<TEntity> where TEntity : class
{
void Add(TEntity entity);
void Update(TEntity entity);
void Delete(int id);
TEntity GetById(int id);
IEnumerable<TEntity> GetAll();
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext _context;
protected readonly DbSet<TEntity> _entities;
public Repository(DbContext context)
{
_context = context;
_entities = context.Set<TEntity>();
}
public virtual void Add(TEntity entity)
{
_entities.Add(entity);
}
public virtual void Update(TEntity entity)
{
_entities.Update(entity);
}
public virtual void Delete(int id)
{
var entity = GetById(id);
_entities.Remove(entity);
}
public virtual TEntity GetById(int id)
{
return _entities.Find(id);
}
public virtual IEnumerable<TEntity> GetAll()
{
return _entities.ToList();
}
}
public interface IUnitOfWork
{
IEmployeeRepository Employees { get; }
ICityRepository Cities { get; }
int SaveChanges();
}
public class UnitOfWork : IUnitOfWork
{
readonly AppDbContext _context;
IEmployeeRepository _employees;
ICityRepository _cities;
public UnitOfWork(AppDbContext context)
{
_context = context;
}
public IEmployeeRepository Employees
{
get
{
if (_employees == null)
_employees = new EmployeeRepository(_context);
return _employees;
}
}
public ICityRepository Cities
{
get
{
if (_cities == null)
_cities = new CityRepository(_context);
return _cities;
}
}
public int SaveChanges()
{
return _context.SaveChanges();
}
}
public interface IEmployeeRepository : IRepository<Employee>
{
bool CheckEmployeeExists(int employeeId, string employeeName);
}
public class EmployeeRepository : Repository<Employee>, IEmployeeRepository
{
public EmployeeRepository(DbContext context) : base(context)
{ }
public bool CheckEmployeeExists(int employeeId, string employeeName)
{
// Implement Dapper code here
}
private AppDbContext _appContext => (AppDbContext)_context;
}
Now, we would like to implement few methods of EmployeeRepository like CheckEmployeeExists to use Dapper. What changes do we need to make in above code considering best coding practices so that both EF and dapper work in proper way. How to integrate Dapper here?
Thank you.
This is for EF Core (EF6 works the same but the methods are slightly different).
Either open/close the underlying DbConnection in each method:
public bool CheckEmployeeExists(int employeeId, string employeeName)
{
var con = context.GetDbConnection();
con.Open();
//use Dapper with DbConnection here
con.Close();
}
If you fail to Close() the connection, it will be closed by DbContext.Dispose(), so it's not critical to Close() and you must not call Dispose() here.
Or Open the connection in the constructor, then it will be available to any method for the lifetime of the DbContext, eg
public EmployeeRepository(DbContext context) : base(context)
{
this.con = context.GetDbConnection();
con.Open();
}
Using Autofac, I tried to use my generic type :
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(Expression<Func<T, bool>> where);
T GetById(long Id);
T GetById(string Id);
T Get(Expression<Func<T, bool>> where);
IEnumerable<T> GetAll();
IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
}
to register my generic class :
public abstract class RepositoryBase<T> where T : class
{
private iMOSSContainer dataContext;
private readonly IDbSet<T> dbset;
protected RepositoryBase()
{
DatabaseFactory = new DatabaseFactory();
dbset = DataContext.Set<T>();
}
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get;
private set;
}
protected iMOSSContainer DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
public virtual void Update(T entity)
{
dbset.Attach(entity);
dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
dbset.Remove(entity);
}
public virtual void Delete(Expression<Func<T, bool>> where)
{
IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
foreach (T obj in objects)
dbset.Remove(obj);
}
public virtual T GetById(long id)
{
return dbset.Find(id);
}
public virtual T GetById(string id)
{
return dbset.Find(id);
}
public virtual IEnumerable<T> GetAll()
{
return dbset.ToList();
}
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return dbset.Where(where).ToList();
}
public T Get(Expression<Func<T, bool>> where)
{
return dbset.Where(where).FirstOrDefault<T>();
}
}
this way :
var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(RepositoryBase<>)).As(typeof(IRepository<>)); //.InstancePerLifetimeScope();
Container = builder.Build();
And returns an error "sequence contains no element" when building a container.
Did i do something wrong with the code? I already tried to search for an answer to no avail. So, your help would be pretty much appreciated.
Ok, then i changed the RepositoryBase class like this :
public class RepositoryBase<T> : IRepository<T> where T : class
{
private iMOSSContainer dataContext;
private readonly IDbSet<T> dbset;
public RepositoryBase()
{
DatabaseFactory = new DatabaseFactory();
dbset = DataContext.Set<T>();
}
So :
i use the "iRepository" interface (and move the "where T : class"
statement at the end of the line)
i remove the "abstract" class (because it leads to another error)
set the default constructor to "public" (because it leads to another
error, as well)
And everything is working good right now.
Your RepositoryBase type is abstract, therefore it can't be registered. You need to register non-abstract types. I'm guessing what you're intending to do is register all subtypes of RepositoryBase.
Have been implementing Generic Repository, Unit of Work pattern with EF5 Code First from a number of resources and have come up with the following assemblies.
Interfaces, Contexts, Model, Repositories, UnitsOfWork
In the Context assembly I have my migrations folder which contains Configuration.cs
internal sealed class Configuration : DbMigrationsConfiguration<Context.SportsContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(Context.SportsContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
As you can see this DbMigrationsConfiguration takes in my SportsContext which is also defined in the contexts assembly (Contexts folder)
public class SportsContext : IDbContext
{
private readonly DbContext _context;
public SportsContext()
{
_context = new DbContext("SportsContext");
}
public void Dispose()
{
_context.Dispose();
}
public IDbSet<T> GetEntitySet<T>() where T : class
{
return _context.Set<T>();
}
public void ChangeState<T>(T entity, EntityState state) where T : class
{
_context.Entry(entity).State = state;
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
This implements IDbContext which is defined in the Interfaces assembly
public interface IDbContext : IDisposable
{
IDbSet<T> GetEntitySet<T>() where T : class;
void ChangeState<T>(T entity, EntityState state) where T : class;
void SaveChanges();
}
In my UnitsOfWork assembly I have the following class
public class SportUnitOfWork : IUnitofWork
{
private readonly IDbContext _context;
public SportUnitOfWork()
{
_context = new SportsContext();
}
private GenericRepository<Team> _teamRepository;
private GenericRepository<Fixture> _fixtureRepository;
public GenericRepository<Team> TeamRepository
{
get { return _teamRepository ?? (_teamRepository = new GenericRepository<Team>(_context)); }
}
public GenericRepository<Fixture> FixtureRepository
{
get { return _fixtureRepository ?? (_fixtureRepository = new GenericRepository<Fixture>(_context)); }
}
public void Save()
{
_context.SaveChanges();
}
public IDbContext Context
{
get { return _context; }
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
For examples sake I have added the GenericRepository class in the Repositories assembly
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private IDbContext _context;
public GenericRepository(IDbContext context)
{
_context = context;
}
public GenericRepository(IUnitofWork uow)
{
_context = uow.Context;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing) return;
if (_context == null) return;
_context.Dispose();
_context = null;
}
public void Add(T entity)
{
_context.GetEntitySet<T>().Add(entity);
}
public void Update(T entity)
{
_context.ChangeState(entity, EntityState.Modified);
}
public void Remove(T entity)
{
_context.ChangeState(entity, EntityState.Deleted);
}
public T FindSingle(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
{
var set = FindIncluding(includes);
return (predicate == null) ? set.FirstOrDefault() : set.FirstOrDefault(predicate);
}
public IQueryable<T> Find(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
{
var set = FindIncluding(includes);
return (predicate == null) ? set : set.Where(predicate);
}
public IQueryable<T> FindIncluding(params Expression<Func<T, object>>[] includeProperties)
{
var set = _context.GetEntitySet<T>();
if (includeProperties != null)
{
foreach (var include in includeProperties)
{
set.Include(include);
}
}
return set.AsQueryable();
}
public int Count(Expression<Func<T, bool>> predicate = null)
{
var set = _context.GetEntitySet<T>();
return (predicate == null) ? set.Count() : set.Count(predicate);
}
public bool Exist(Expression<Func<T, bool>> predicate = null)
{
var set = _context.GetEntitySet<T>();
return (predicate == null) ? set.Any() : set.Any(predicate);
}
}
The problem I have is in the Configuration class which inherits from DbMigrationsConfiguration is expecting a DbContext parameter.
Error is Error 1 The type 'Contexts.Context.SportsContext' cannot be used as type parameter 'TContext' in the generic type or method 'System.Data.Entity.Migrations.DbMigrationsConfiguration'. There is no implicit reference conversion from 'Contexts.Context.SportsContext' to 'System.Data.Entity.DbContext'.
I can change the SportsContext to also inherit from DbContext but then I need to add a reference to EntityFramework 5 in the UnitsOfWork assembly as we want to possibly change or take out each layer without any reference to underlying models which is why i went with this pattern.
As we are looking at adding further contexts and models in the future so wanted to setup a architecture in that we could just add the context, model and then implement the relevant interfaces as and when needed.
A WebAPI Restful Web Service will be interacting with our data via the SportUnitOfWork, if I have understood the patterns correctly.
If anyone has any ideas on how I could do this or anything that I am doing wrong please let me know
thanks in advance Mark
Resolved this by doing the following
Changed my SportsContext class to a BaseContext which is abstract
public abstract class BaseContext : IDbContext
{
protected DbContext Context;
public void Dispose()
{
Context.Dispose();
}
public IDbSet<T> GetEntitySet<T>() where T : class
{
return Context.Set<T>();
}
public void Add<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Added;
}
public void Update<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Modified;
}
public void Delete<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Deleted;
}
public void SaveChanges()
{
// At the moment we are conforming to server wins when handling concurrency issues
// http://msdn.microsoft.com/en-us/data/jj592904
try
{
Context.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
//Refresh using ServerWins
var objcontext = ((IObjectContextAdapter) Context).ObjectContext;
var entry = e.Entries;
objcontext.Refresh(RefreshMode.StoreWins, entry);
SaveChanges();
}
}
private DbEntityEntry GetDbEntityEntrySafely<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = Context.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
// Set Entity Key
var objcontext = ((IObjectContextAdapter) Context).ObjectContext;
if (objcontext.TryGetObjectByKey(dbEntityEntry.Entity))
Context.Set<T>().Attach(entity);
}
return dbEntityEntry;
}
}
created in the Context folder a new class called FootballContext which inherits from BaseContext.
public class FootballContext : BaseContext
{
public FootballContext(string connectionstringName)
{
Context = new BaseFootballContext(connectionstringName);
}
}
Created a new folder called DbContexts
In here created the following classes,
public class BaseFootballContext : DbContext
{
public BaseFootballContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
public IDbSet<Fixture> Fixtures { get; set; }
public IDbSet<Team> Teams { get; set; }
}
public class MigrationsContextFactory : IDbContextFactory<BaseFootballContext>
{
public BaseFootballContext Create()
{
return new BaseFootballContext("FootballContext");
}
}
now my Configuration class can take in the BaseFootballContext as this is a DbContext.
My UnitOfWork class can now set the context to be FootballContext so does not have to reference EntityFramework.
This works with Migrations as well.
Only problem I have now is to figure out how to get this to work in a disconnected environment as I am having a problem reattaching entities and applying updates.
Note: I am using Entity Framework version 5
Inside my generic repository, I have Add, Edit and Delete methods as below:
public class EntityRepository<T> : IEntityRepository<T>
where T : class, IEntity, new() {
readonly DbContext _entitiesContext;
public EntityRepository(DbContext entitiesContext) {
if (entitiesContext == null) {
throw new ArgumentNullException("entitiesContext");
}
_entitiesContext = entitiesContext;
}
//...
public virtual void Add(T entity) {
DbEntityEntry dbEntityEntry = _entitiesContext.Entry<T>(entity);
if (dbEntityEntry.State != EntityState.Detached) {
dbEntityEntry.State = EntityState.Added;
}
else {
_entitiesContext.Set<T>().Add(entity);
}
}
public virtual void Edit(T entity) {
DbEntityEntry dbEntityEntry = _entitiesContext.Entry<T>(entity);
if (dbEntityEntry.State == EntityState.Detached) {
_entitiesContext.Set<T>().Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}
public virtual void Delete(T entity) {
DbEntityEntry dbEntityEntry = _entitiesContext.Entry<T>(entity);
if (dbEntityEntry.State != EntityState.Detached) {
dbEntityEntry.State = EntityState.Deleted;
}
else {
DbSet dbSet = _entitiesContext.Set<T>();
dbSet.Attach(entity);
dbSet.Remove(entity);
}
}
}
Do you think whether these methods are well implemented? Especially the Add method. Would it be better to implement the Add method as below?
public virtual void Add(T entity) {
DbEntityEntry dbEntityEntry = _entitiesContext.Entry<T>(entity);
if (dbEntityEntry.State == EntityState.Detached) {
_entitiesContext.Set<T>().Attach(entity);
}
dbEntityEntry.State = EntityState.Added;
}
For add:
public bool Add<E>(E entity) where E : class
{
DataContext.Entry(entity).State = System.Data.EntityState.Added;
Save();
}
For update:
public bool Update<E>(E entity) where E : class
{
DataContext.Entry(entity).State = System.Data.EntityState.Modified;
Save();
}
For delete:
public bool Delete<E>(E entity) where E : class
{
DataContext.Entry(entity).State = System.Data.EntityState.Deleted;
Save();
}
And a private Save() method that returns true or false so you can fallback easy in the controller depending on the result
private bool Save()
{
return DataContext.SaveChanges() > 0;
}
This is only a portion of my generic repository. It works great in enterprise applications.
UPDATE:
Detach only affects the specific object passed to the method. If the
object being detached has related objects in the object context, those
objects are not detached.
EF will automatically attach detached objects in the graph when setting the state of an entity or when SaveChanges() is called.
I really don't know why you need to detach objects from the context. You can also use AsNoTracking() to load entities from the database without attaching them to the context in the first place.
I'm playing with the latest Entity Framework CTP 5 release and building a simple asp.net MVC blog where I just have two tables: Post and Comments. This is done entirely in POCO, I just need help on the DbContext part, where I need it to be unit testable (using IDbSet?) and I need a simple/generic repository pattern for add, update, delete, retrieval. Any help is appreciated.
Thanks.
Start with you DbContext, create a new file called Database.cs:
Database.cs
public class Database : DbContext
{
private IDbSet<Post> _posts;
public IDbSet<Post> Posts {
get { return _posts ?? (_posts = DbSet<Post>()); }
}
public virtual IDbSet<T> DbSet<T>() where T : class {
return Set<T>();
}
public virtual void Commit() {
base.SaveChanges();
}
}
Define a IDatabaseFactory and implement it with DatabaseFactory:
IDatabaseFactory.cs
public interface IDatabaseFactory : IDisposable
{
Database Get();
}
DatabaseFactory.cs
public class DatabaseFactory : Disposable, IDatabaseFactory {
private Database _database;
public Database Get() {
return _database ?? (_database = new Database());
}
protected override void DisposeCore() {
if (_database != null)
_database.Dispose();
}
}
Disposable extension method:
Disposable.cs
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
Now we can define our IRepository and our RepositoryBase
IRepository.cs
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> AllReadOnly();
}
RepositoryBase.cs
public abstract class RepositoryBase<T> where T : class
{
private Database _database;
private readonly IDbSet<T> _dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = Database.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected Database Database
{
get { return _database ?? (_database = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
_dbset.Remove(entity);
}
public virtual void Update(T entity)
{
_database.Entry(entity).State = EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset.ToList();
}
public virtual IEnumerable<T> AllReadOnly()
{
return _dbset.AsNoTracking().ToList();
}
}
Now you can create your IPostRepository and PostRepository:
IPostRepository.cs
public interface IPostRepository : IRepository<Post>
{
//Add custom methods here if needed
Post ByTitle(string title);
}
PostRepository.cs
public class PostRepository : RepositoryBase<Post>, IPostRepository
{
public PostRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
public Post ByTitle(string title) {
return base.Database.Posts.Single(x => x.Title == title);
}
}
Lastly, the UoW:
IUnitOfWork.cs
public interface IUnitOfWork
{
void Commit();
}
UnitOfWork.cs
private readonly IDatabaseFactory _databaseFactory;
private Database _database;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
protected Database Database
{
get { return _database ?? (_database = _databaseFactory.Get()); }
}
public void Commit()
{
Database.Commit();
}
Using in your controller:
private readonly IPostRepository _postRepository;
private readonly IUnitOfWork_unitOfWork;
public PostController(IPostRepository postRepository, IUnitOfWork unitOfWork)
{
_postRepository = postRepository;
_unitOfWork = unitOfWork;
}
public ActionResult Add(Post post) {
_postRepository.Add(post);
_unitOfWork.Commit();
}
You will need to use an IoC container like StructureMap to make this work. You can install structure map via NuGet, or if you are using MVC 3, you can install the StructureMap-MVC NuGet package. (Links Below)
Install-Package StructureMap.MVC4
Install-Package StructureMap.MVC3
Install-Package Structuremap
If you have questions just let me know. Hope it helps.
I just love this in-depth article about Entity Framework 4 POCO, Repository and Specification Pattern
http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/
The only thing I'd do differently is in the implementation, i.e. expose the IPostRepository in the service layer and have an interface field of type IPostService in the controller just as another layer of abstraction but otherwise this is a good example - nice one, Paul.