Generic repository implementation with EF

2019-05-31 10:35发布

问题:

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.

回答1:

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.



回答2:

Because you tagged your question with entity-framework and entity-framework-4 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:

  • Generic GetById with DbContext
  • Generic GetById with ObjectContext


回答3:

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



回答4:

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