In some previous posts (here and here) I was describing some ideas related to fluent repositories.
Here is an idea to bring some of that functionality into a base repository, and obtain less repetitive code:
public class BaseRepository<EntityType, PKType, RepositoryType> where RepositoryType : class
{
protected ICriteria _criteria;
protected ISession Session
{
get
{
return SessionHolder.Current;
}
}
public RepositoryType InitialiseCriteriaFor ( PKType id )
{
InitialiseCriteria();
_criteria.Add(Restrictions.Eq("Id", id));
return this as RepositoryType;
}
public RepositoryType InitialiseCriteria ( )
{
return InitialiseCriteria("");
}
public virtual RepositoryType InitialiseCriteria ( string alias )
{
if (IEnumerableExtensions.IsEmpty(alias))
_criteria = Session.CreateCriteria(typeof(EntityType));
else
{
_criteria = Session.CreateCriteria(typeof(EntityType), alias);
}
return this as RepositoryType;
}
private BaseRepository<EntityType, PKType, RepositoryType> OnlyActive ( )
{
IActivable activable = this as IActivable;
if (activable == null) return this;
_criteria.Add(Restrictions.Eq(activable.IsActiveField, true));
return this;
}
private BaseRepository<EntityType, PKType, RepositoryType> Sorted ( )
{
ISortable sortable = this as ISortable;
if (sortable == null) return this;
_criteria.AddOrder(new Order(sortable.SortField, sortable.Ascending));
return this;
}
public RepositoryType InitialiseListCriteria ( )
{
InitialiseCriteria();
return OnlyActive().Sorted() as RepositoryType;
}
public EntityType LoadEntity ( )
{
return _criteria.UniqueResult<EntityType>();
}
public IList<EntityType> LoadList ( )
{
return _criteria.List<EntityType>();
}
public ICriteria GetCurrentCriteria ( )
{
return _criteria;
}
public RepositoryType ByIds ( IEnumerable<PKType> ids )
{
_criteria.Add(Restrictions.In("Id", (ICollection)ids));
return this as RepositoryType;
}
public RepositoryType MaxResults ( int maxResults )
{
_criteria.SetMaxResults(maxResults);
return this as RepositoryType;
}
public virtual bool Ascending
{
get
{
return true;
}
}
}
The generic signature contains the type of the repository, but the same result could be obtained with reflection and the parameter would dissapear. I am also using 2 sample interfaces, which bring default sorting and filtering behavior into the BaseRepository:
public interface ISortable
{
string SortField { get; }
bool Ascending { get; }
}
public interface IActivable
{
string IsActiveField { get; }
}
Here is how a simple repository would look:
public class TagRepository: BaseRepository<Tag, int, TagRepository>, ISortable
{
public TagRepository ByTagNames(IList<string> tags)
{
_criteria.Add(Restrictions.InG("TagName", tags));
return this;
}
public string SortField
{
get { return "TagCount"; }
}
}
and here is how it can be used:
IList<Tag> existingTags = _tagRepository.InitialiseListCriteria().ByTagNames(crtTagNames).LoadList();
This will load all tags which have a name from the given list, and sort them by TagCount.
The BaseRepository above contains a few more options, and others can easily be added.