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.
Related
I have a project broken into separate classes for an MVC project using Entity Framework 6. One class has a Generic Interface and then it is inherited
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
}
Inherited as below
public class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext _context = null;
private readonly DbSet<T> _entities;
public GenericRepository(DbContext context)
{
_context = context;
_entities = _context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entities;
}
}
This works fine and i then use this in a customer class as below
public class CustomerRepository : Repository<Customer>, ICustomerRepository
{
public CustomerRepository(DataContext context) : base(context)
{
}
public List<Customer> GetPremiumCustomers()
{
return GetAll().Where(p => p.Premium).ToList();
}
}
So far so good and everything returns as expected.
I need to Include a couple of additional tables that are linked to the customers.
When i go to the Repository class and against _entities i press the . key i see Include in the menu.
I then go into the CustomerRepository and do the same with GetAll(). and along other methods along that line but Include isnt shown?
I tried adding using System.Data.Entity to the top of the Customer class but that didnt bring the option either but it is available in the top most class? What am i missing here?
I was trying to achieve something along the lines of
GetAll().Include("Address").Where(p => p.Premium).ToList()
In Entity Framework 6, the Include method is defined on the DbQuery<T> class (DbSet<T> is derived from DbQuery<T>). Your GetAll method on the other hand returns an IEnumerable<T>. The compiler does not know that you return a DbSet<T> in the form of the IEnumerable<T>, hence the method is not offered.
If you want to offer the caller of GetAll to use the Include method, you can change the return type, e.g.:
public interface IRepository<T> where T : class
{
DbQuery<T> GetAll();
}
Please note by using DbQuery<T> as your return type, the interface shows that you are using Entity Framework and you do not hide this detail from the user of the interface. In order to hide this, you can offer another method that accepts a parameter for the include and still returns an IEnumerable<T>:
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
IEnumerable<T> GetAllWithInclude(string include);
}
public class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext _context = null;
private readonly DbSet<T> _entities;
public GenericRepository(DbContext context)
{
_context = context;
_entities = _context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entities;
}
public IEnumerable<T> GetAllWithInclude(string include)
{
return _entities.Include(include);
}
}
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>();
}
}
I know that this question seems to be already made here, but I have specific doubts, mainly in database-first usage and lack of code-example in replied questions.
I have these layers: Core, Data and UI (asp.net mvc).
I have these tables in MSSQL: Person and Contact.
Question 1: In data layer, EDMX generates Person and Data POCO. Where I write methods like SearchPersonByCity() ? Do I need to create another Person class in the same data layer, just for writting data CRUD? How I make this? Please make an example (classes, namespaces, etc.. not necessary the whole actual code)
Question 2: How do I transpose these data between data-layer and core (domain models)? Where do I need to create the same SearchPersonByCity() in core (domain) class? Maybe create another Person class in core-layer just for these data-acess methods?
Please give me some code example, and how big companies do in real life, because it seems to be so dumb and a lot of code to mantain and problaby I'm getting something wrong.
I'm not lazy, and I read hundreds pages of Entity Framework books, questions here, and I can't figure out how to do this in code.
In my opinion I would use the repository pattern in your case, so first you have a IRepository class defined:
public interface IRepository<T> where T :
{
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);
}
And an abstract base RepositoryBase class:
public abstract class RepositoryBase<T> where T : class
{
private PersonDBEntities dataContext;
private readonly IDbSet<T> dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get;
private set;
}
protected PersonDBEntities 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();
}
//You can return IQueryable if you want to build your expression true later on...
public virtual IEnumerable<T> Get(Expression<Func<T, bool>> where)
{
return dbset.Where(where).ToList();
}
}
And your PersonRepository class:
public class PersonRepository: RepositoryBase<Person>, IPersonRepository
{
public PersonRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
}
public interface IPersonRepository : IRepository<Person> // Person will be your POCO class
{
}
Next step is on your service layer, you will define and implement that actual SearchPersonByCity() method:
public class PersonService : IPersonService
{
private readonly IPersonRepository personRepository;
private readonly IUnitOfWork unitOfWork;
public PersonService(IPersonRepository personRepository, IUnitOfWork unitOfWork)
{
this.personRepository = personRepository;
this.unitOfWork = unitOfWork;
}
public IEnumerable<Person> SearchPersonByCity(string city)
{
var persons = personRepository.Get(p => p.City == city);
return persons;
}
}
My application is getting larger and so far I have a single MyDbContext which has all the tables I need in my application. I wish (for the sake of overview) to split them up into multiple DbContext, like MainDbContext, EstateModuleDbContext, AnotherModuleDbContext and UserDbContext.
I am unsure how this is done probably as I am right now using dependecy injection (ninject) to place my DbContext on my UnitOfWork class like:
kernel.Bind(typeof(IUnitOfWork)).To(typeof(UnitOfWork<MyDbContext>));
Should I drop this approach with dependency injection and explicit set the DbContext I wish to use on my services like:
private readonly EstateService _estateService;
public HomeController()
{
IUnitOfWork uow = new UnitOfWork<MyDbContext>();
_estateService = new EstateService(uow);
}
Instead of:
private readonly EstateService _estateService;
public HomeController(IUnitOfWork uow)
{
_estateService = new EstateService(uow);
}
Or this there another better approach? Also as a side question, I dont like passing the uow to my service - is there another (better) approach?
Code
I have this IDbContext and MyDbContext:
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
int SaveChanges();
void Dispose();
}
public class MyDbContext : DbContext, IDbContext
{
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table1 { get; set; }
public DbSet<Table3> Table1 { get; set; }
public DbSet<Table4> Table1 { get; set; }
public DbSet<Table5> Table1 { get; set; }
/* and so on */
static MyDbContext()
{
Database.SetInitializer<MyDbContext>(new CreateDatabaseIfNotExists<MyDbContext>());
}
public MyDbContext()
: base("MyDbContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
Then I have this IRepository and the implementation:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
void Add(T entity);
void Delete(T entity);
void DeleteAll(IEnumerable<T> entity);
void Update(T entity);
bool Any();
}
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 virtual IQueryable<T> GetAll()
{
return _dbset;
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
var entry = _context.Entry(entity);
entry.State = EntityState.Deleted;
_dbset.Remove(entity);
}
public virtual void DeleteAll(IEnumerable<T> entity)
{
foreach (var ent in entity)
{
var entry = _context.Entry(ent);
entry.State = EntityState.Deleted;
_dbset.Remove(ent);
}
}
public virtual void Update(T entity)
{
var entry = _context.Entry(entity);
_dbset.Attach(entity);
entry.State = EntityState.Modified;
}
public virtual bool Any()
{
return _dbset.Any();
}
}
And the IUnitOfWork and implemention which handles the work done with the DbContext
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
private readonly IDbContext _ctx;
private readonly Dictionary<Type, object> _repositories;
private bool _disposed;
public UnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
_disposed = false;
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
// Checks if the Dictionary Key contains the Model class
if (_repositories.Keys.Contains(typeof(TEntity)))
{
// Return the repository for that Model class
return _repositories[typeof(TEntity)] as IRepository<TEntity>;
}
// If the repository for that Model class doesn't exist, create it
var repository = new Repository<TEntity>(_ctx);
// Add it to the dictionary
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void Save()
{
_ctx.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (this._disposed) return;
if (disposing)
{
_ctx.Dispose();
}
this._disposed = true;
}
}
Don't split your modular data pieces into multiple DbContexts unless there are logical seams for doing so. Entities from DbContextA cannot have automatic navigation or collection properties with entities in DbContextB. If you split the context, your code would have to be responsible for manually enforcing constraints and loading related data between contexts.
For "sake of overview" (a.k.a. keeping your sanity), you can still organize your CLR code and database tables by module. For the POCO's, keep them in different folders under different namespaces. For tables, you can group by schema. (However you probably should also take security considerations into account when organizing by SQL schema. For example, if there are any db users that should have restricted access to certain tables, design the schemas according to those rules.) Then, you can do this when building the model:
ToTable("TableName", "SchemaName"); // put table under SchemaName, not dbo
Only go with a separate DbContext when its entities have no relationships with any entities in your first DbContext.
I also agree with Wiktor in that I don't like your interface & implementation design. I especially don't like public interface IRepository<T>. Also, why declare multiple public DbSet<TableN> TableN { get; set; } in your MyDbContext? Do me a favor, read this article, then read this one.
You can greatly simplify your code with an EF interface design like this:
interface IUnitOfWork
{
int SaveChanges();
}
interface IQueryEntities
{
IQueryable<T> Query<T>(); // implementation returns Set<T>().AsNoTracking()
IQueryable<T> EagerLoad<T>(IQueryable<T> queryable, Expression<Func<T, object>> expression); // implementation returns queryable.Include(expression)
}
interface ICommandEntities : IQueryEntities, IUnitOfWork
{
T Find<T>(params object[] keyValues);
IQueryable<T> FindMany<T>(); // implementation returns Set<T>() without .AsNoTracking()
void Create<T>(T entity); // implementation changes Entry(entity).State
void Update<T>(T entity); // implementation changes Entry(entity).State
void Delete<T>(T entity); // implementation changes Entry(entity).State
void Reload<T>(T entity); // implementation invokes Entry(entity).Reload
}
If you declare MyDbContext : ICommandEntities, you just have to set up a few methods to implement the interface (usually one-liners). You can then inject any of the 3 interfaces into your service implementations: usually ICommandEntities for operations that have side effects, and IQueryEntities for operations that don't. Any services (or service decorators) responsible only for saving state can take a dependency on IUnitOfWork. I disagree that Controllers should take a dependency on IUnitOfWork though. Using the above design, your services should save changes before returning to the Controller.
If having multiple separate DbContext classes in your app ever makes sense, you can do as Wiktor suggests and make the above interfaces generic. You can then dependency inject into services like so:
public SomeServiceClass(IQueryEntities<UserEntities> users,
ICommandEntities<EstateModuleEntities> estateModule) { ... }
public SomeControllerClass(SomeServiceClass service) { ... }
// Ninject will automatically constructor inject service instance into controller
// you don't need to pass arguments to the service constructor from controller
Creating wide per-aggregate (or even worse per-entity) repository interfaces can fight with EF, multiply boring plumbing code, and over-inject your constructors. Instead, give your services more flexibility. Methods like .Any() don't belong on the interface, you can just call extensions on the IQueryable<T> returned by Query<T> or FindMany<T> from within your service methods.
Your unit of work interface is not generic but the implementation is. The easiest way to clean up this would be to decide and follow the same convention.
For example, make your interface generic also. This way you could register three different interfaces (the same interface with three different generic parameters) to three different implementations:
container.Bind( typeof<IUnitOfWork<ContextOne>> ).To( typeof<UnitOfWork<ContextOne>> );
...
And yes, this is a good idea to inject your unit of works into controllers / services.
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);
}
}