3

I'm trying to streamline my existing repos by using a generic repo I can subclass from. The problem is that I can't figure out how to write a few of my base class methods. I currently have:

public interface IRepository<T> : IDisposable where T : class
{
    IQueryable<T> GetAll();
    T GetSingle(int id);
    T GetSingle(string slug);
    void Save(T entity);
}

public class HGRepository<T> : IRepository<T> where T : class
{
    protected HGEntities _siteDB;
    protected IObjectSet<T> _objectSet;

    public HGRepository(HGEntities context)
    {
        _siteDB = context;
        _objectSet = _siteDB.CreateObjectSet<T>();
    }

    public IQueryable<T> GetAll()
    {
        return _objectSet;
    }

    public T GetSingle(int id)
    {
        return null;
    }

    public T GetSingle(string slug)
    {
        return null;
    }

    public void Save(T entity)
    {
        // code to save entity
    }

    public void Dispose()
    {
        _siteDB = null;
    }
}

My confusion lies with my GetSingle() and Save() methods. They'll need to rely on information that's slightly different with each type of T. Example from my non-generic repos:

public Article GetArticle(int id)
{
    return _siteDB.Articles.SingleOrDefault(a => a.ArticleID == id);
}

public Article GetArticle(string slug)
{
    return _siteDB.Articles.SingleOrDefault(a => a.Slug == slug);
}

public void SaveArticle(Article article)
{
    if (article.ArticleID > 0)
    {
        _siteDB.ObjectStateManager.ChangeObjectState(article, System.Data.EntityState.Modified);
    }
    else
    {
        _siteDB.Articles.AddObject(article);
    }

    _siteDB.SaveChanges();
}

As you can see, Articles have their own, specific id. The same thing for my other entities (News items have a NewsID property, for instance).

How can I make an abstract base method that can be reconciled into a more specific version?

Yusubov
  • 5,815
  • 9
  • 32
  • 69
Major Productions
  • 5,914
  • 13
  • 70
  • 149
  • 1
    First question should be [_why_ use repository](http://stackoverflow.com/a/5488947/861716). – Gert Arnold Jun 22 '12 at 06:22
  • Great link. That said, my project is fairly simple, and my back end is really just simple CRUD functionality. No DDD in it. – Major Productions Jun 22 '12 at 12:59
  • 1
    Even more reason to abstain from sandbag code, isn't it? – Gert Arnold Jun 22 '12 at 13:15
  • Hmmm... maybe. To me, it would be cleaner for something like the code I use to save entities, an example of which is in my question above, to be hidden away behind a method interface. But, on the other hand, the GetByXXX methods remind me of ugly PHP boilerplate. – Major Productions Jun 22 '12 at 13:47

1 Answers1

3

You can have a generic expression parameter for your GetSingle method:

public interface IRepository<T> : IDisposable where T : class
{
    ....
    T GetSingle(Expression<Func<T, bool>> filter);
    void Save(T entity);
}

and in HGRepository<T>:

public T GetSingle(Expression<Func<T, bool>> filter)
{
        return _objectSet.Where(filter).SingleOrDefault();
}

And usage:

IRepository<Article> rep = new HGRepository<Article>();
return rep.GetSingle(p => p.Slug == slug);

If you have particular scenarios which the generic interface / repository class don't cover, you can create new interface / class which inherit from the generic ones:

public interface IArticleRepository : IRepository<Article>
{
   ...
}

public class ArticleRepository : HGRepository<Article>, IArticleRepository
{
   ...
}
Major Productions
  • 5,914
  • 13
  • 70
  • 149
dan radu
  • 2,772
  • 4
  • 18
  • 23