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);
}
}
Related
I am developing an application in Asp.net MVC core in which i using a generic interface which is as below :
public interface IRepository<TEntity, TKeyType> where TEntity : class where TKeyType : struct
{
TEntity Add(TEntity entity);
}
And below is the implementation of it.
public class EntityRepository<TEntity, TKeyType> : IRepository<TEntity, TKeyType> where TEntity : class where TKeyType : struct
{
protected readonly DrinkDbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DrinkDbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public virtual TEntity Add(TEntity entity)
{
Context.Add(entity);
return entity;
}
}
Futher, I am inheriting EntityRepository class in ShoppingCartRepository which is as below :
public class ShoppingCartRepository<ShoppingCartItem, Int32> : EntityRepository<ShoppingCartItem, Int32>
where ShoppingCartItem : class where Int32 : struct
{
public ShoppingCartRepository(DrinkDbContext context) : base(context) { }
public override ShoppingCartItem Add(ShoppingCartItem entity)
{
base.Add(entity);
return entity;
}
}
and able to see the populated properties of a class in a method at the runtime. Please find the screenshot as below :
But when try to use those properties at compile time, i am unable to see those properties. Please find the screenshot as below.
How can i access the properties of ShoppingCartItem which is passed in Add method as a parameter ?
The issue is your ShoppingCartRepository is viewed as a generic.
ShoppingCartRepository<ShoppingCartItem,int> -> In this scenario ShoppingCartItem is of type class which you have constrained it.
It is like writing ShoppingCartRepository<T,int>. So your ShoppingCartItem is not viewed as a type ShoppingCartItem but as a generic of type T where T : class.
So class does not have access to ShoppingCartItem's properties inside the Add method.
Update to this:
public class ShoppingCartRepository : EntityRepository<ShoppingCartItem, Int32>
This make your ShoppingCartRepository non generic.
I do not think you want the ShoppingCartRepository generic, since you are specifying implementation for ShoppingCartItem.
With the above change. You should have access to the ShoppingCartItem properties inside the Add method.
partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
My generic repository implements a common set of methods for TEntity like
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
which I can access like
Repository<User>().Get();
Many repositories does the same set of operation, so it is beneficial but now I want to extend Repository<User> to support some additional behavior.
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
so that I can use the repository like
Repository<User>().DoMagicFunction();
how can I extend the same generic class for Some Tentity to extend new behaviour instead of modifying it.
I could have done the same like creating another UserRepository to support new feature, but the accessor would become
UserRepository.DoMagicFunction();
but I want it to be like
Repository<User>().DoMagicFunction();
You can use an extension method:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
This will thus add the function in a syntactically nice way to Repository<User> objects.
In case you want to support it not only for Users, but for subclasses of Users as well, you can make the function generic:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C# has a language feature called Extension Methods, you probably are using them from the .NET framework without knowing (e.g. the linq extensions methods). It's common to extend your classes or even your interfaces with extension methods without breaking the functionality of your code. Here is an example for your case.
Suppose you have a generic IRepository interface:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
This interface adheres to the SOLID principles, especially the O and I principle.
Now suppose IEntity looks like this:
public interface IEntity
{
int Id { get; }
}
Now you could perfectly imagine an often reusable extension method like this:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
In a similar manner you could also extend your Repository class
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
You can now consume that like this:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
You could also limit your extension method:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
But doing this will defeat it's purpose, you could rather just implement this in the Repository<User> class.
If your system and architecture uses Dependency Injection, you're probably injecting an IRepository<User> to your consuming classes. So the first or second extension method examples I've provided would make the most sense.
If you want to extend any repository you can do it like this.
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
For a specific repository (eg User repository) you can use a similar process
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
Extension methods are not the way to go, because the code that implements the method can only access public/internal members of the class they extend and you are likely to want your repository's DataContext to be private.
In my opinion, your approach needs to be changed slightly.
What if in the future you want to add a Delete method to your generic repository, but you have some entities that should never be deleted? You'll end up with an instance of a repository for something like PurchaseOrder that you'll either have to remember to never call delete on or you will have to create a descendant of Repository<T> that throws an InvalidOperationException if called. Both of which are poor implementations.
Instead, you should delete your IRepository<T> interface completely. Keep your Repository<T> class, but explicitly define a repository interface for every entity that only has the methods you require.
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
When you need additional methods on your repository you add them to your IPurchaseOrderRepository and create a descendant of Repository<T>
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
Extension method is a best choice for this case.
Note: I have not checked but you should check Dependency Injection still works well as normal.
You can use below code for testing:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}
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.
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);
}
}
I have a pretty straightforward generic repository:
public interface IRepository<TEntity, TNotFound>
where TEntity : EntityObject
where TNotFound : TEntity, new()
{
IList<TEntity> GetAll();
TEntity With(int id);
TEntity Persist(TEntity itemToPersist);
void Delete(TEntity itemToDelete);
}
I want to define a contract for a repository for the type Term without any special behaviour. So it looks like this:
public class TermNotFound : Term
{ public TermNotFound() : base(String.Empty, String.Empty) { } }
public interface ITermRepository : IRepository<Term, TermNotFound> { }
Now for testing, I want to create an in-memory implementation of the generic repo, so I have this (not finished for brevity):
public class InMemoryRepository<TEntity, TNotFound> : IRepository<TEntity, TNotFound>
where TEntity : EntityObject
where TNotFound : TEntity, new()
{
private IList<TEntity> _repo = new List<TEntity>();
public IList<TEntity> GetAll()
{
return this._repo;
}
public TEntity With(int id)
{
return this._repo.SingleOrDefault(i => i.Id == id) ?? new TNotFound();
}
public TEntity Persist(TEntity itemToPersist)
{
throw new NotImplementedException();
}
public void Delete(TEntity itemToDelete)
{
throw new NotImplementedException();
}
}
It's not hard to see how I want it to work. For my tests, I want the generic InMemoryRepository implementation to be injected to create my ITermRepository. How hard is that right?
Well, I can't get StructureMap to do it. I have tried using WithDefaultConventions and ConnectImplementationsToTypesClosing(typeof(IRepository<,>)) in the scanner without success.
Can someone please help me out?
Your InMemoryRepository doesn't implement ITermRepository interface. That's why you can't connect them.
The best thing you could do with what you have is injecting InMemoryRepository<Term, TermNotFound> for IRepository<Term, TermNotFound>.
If you really need to inject ITermRepository, then you'll need to have another repository class inheriting from InMemoryRepository and implementing ITermRepository:
public class InMemoryTermRepository
: InMemoryRepository<Term, TermNotFound>, ITermRepository
{
}
Now you can connect ITermRepository to InMemoryTermRepository using:
.For<ITermRepository>().Use<InMemoryTermRepository>()
If you have many interfaces like ITermRepository, you could create a StructureMap convention, to connect I...Repository to InMemory...Repository. The default convention is to connect IClass to Class.