I like the repository-filter pattern. It allows you to separate concerns from the middle and data end tier without sacrificing performance.
Your data layer can concentrate on simple list-get-save style operations, while your middle tier can utilize extensions to IQueryable to provide more robust functionality:
Repository (Data layer):
public class ThingRepository : IThingRepository
{
public IQueryable<Thing> GetThings()
{
return from m in context.Things
select m; // Really simple!
}
}
Filter (Service layer):
public static class ServiceExtensions
{
public static IQueryable<Thing> ForUserID(this IQueryable<Thing> qry, int userID)
{
return from a in qry
where a.UserID == userID
select a;
}
}
Service:
public GetThingsForUserID(int userID)
{
return repository.GetThings().ForUserID(userID);
}
This is a simple example, but filters can be safely combined to build more complicated queries. The performance is saved because the list isn't materialized until all the filters have been built into the query.
I love it because I dislike application-specific repositories!