问题
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?
回答1:
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
{
...
}
来源:https://stackoverflow.com/questions/11149272/ef4-how-to-use-a-generic-repository-pattern