1

For a simple repository

public interface ISimpleRepository<T>
{
    IApplicationState AppState { get; set; }
    void Add(T instance);
    void Delete(T instance);
    void Delete(Guid rowGuid);
    IQueryable<T> GetAll();
    T Load(Guid rowGuid);
    void SaveChanges();
    void Update(T instance);
}

my implementation of the Load() method for specific repository for class Product might look like this:

    public Product Load(Guid rowid)
    {
        return (from c in _ctx.Products where c.id == rowid select c).FirstOrDefault();
    }

Now this is assumed when my repository implementation class looks like this:

public class EntityFrameworkProductsProvider : IRepository<Product> ...

What if I had like dozens or hundreds of this small and simple entities that would all use the same behaviour when doing CRUDs (use the same implementation of methods)? I certainly don't want to go and create a class to implement IRepository for each one of them..

I want something like this:

public class EntityFrameworkDefaultProvider<T> : IRepository<T> ...

but I don't know how to implement the LINQ Select expression then because of course I can't write from e in _ctx.T where e... or do I?

I haven't run into this scenario yet because so far I only had very specific entities with custom repository implementation.

mare
  • 13,033
  • 24
  • 102
  • 191

4 Answers4

4

Because you tagged your question with and I assume you are using ObjectContext API. ObjectContext offers method CreateObjectSet<T> which is equivalent of Set<T> on DbContext.

This question is actually duplicate of either:

Community
  • 1
  • 1
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
3

Instead of writing _ctx.Products, you can write _ctx.Set<T>. That takes care of half of the problem (you need to add a generic constraint where T: class to your repository)

Then, if rowid is the object's key, you can use _ctx.Set<T>.Find(rowid) instead of a LINQ query to retrieve by Id.

Alternatively, you can create a base interface IHaveId (or a BaseEntity class, whatever you like) which has the Id property, and then add that as an generic constraint on T, so you can use it in your queries.

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • @Diego Mijelshon: What if the id contains more then 1 column? – Naor Apr 25 '11 at 21:53
  • @Naor: they don't according to his interface. It's a bad practice anyway, but `Find` supports passing an `object[]` (as `params`), so he could theoretically add that too. – Diego Mijelshon Apr 25 '11 at 23:47
  • @Diego Mijelshon: But how the Find method knows how to map each object to each key? I asked Ladislav Mrnka also in http://stackoverflow.com/questions/5166297/generic-repository-ef4-ctp5-getbyid/5167709#5167709. – Naor Apr 26 '11 at 01:03
  • @Naor: By the order in which they are defined using the `HasKey` method. See http://msdn.microsoft.com/en-us/library/gg671266(v=VS.103).aspx – Diego Mijelshon Apr 26 '11 at 01:29
  • @Diego Mijelshon: And where does the HashKey defined? – Naor Apr 26 '11 at 01:48
  • @Naor: I have just sent you the link. It's all in the docs. And blog posts by the ADO.NET team. – Diego Mijelshon Apr 26 '11 at 02:11
2

If you're using EF 4.1, see the sample generic repository here: http://www.asp.net/entity-framework/tutorials/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

tdykstra
  • 5,880
  • 2
  • 23
  • 20
1

I know that this is possible in EF4.1 with the DbContext API, where you have a "Set" method on the context that gets you the entity set corresponding to the type T. this way, you could have your repository like this:

public class EntityFrameworkDefaultProvider<T> : IRepository<T> where T:class
{
    public T Load(Guid rowId)
    {
        return _context.Set<T>().Find(rowId);
    }
}

one more remark: I think you could use this syntax :

return _ctx.Products.FirstOrDefault(c=>c.id == rowid);

to get the entity you want instead of using the (from... in...). it's clearer (in my opinion) :)

Hope this helps

AbdouMoumen
  • 3,814
  • 1
  • 19
  • 28