How should I expose the total record count and IEnumable collection of paged records from my service layer method?
I am using EF4 with code first and have a repository for persistence and a service layer that interacts with it. I have a service layer method that calls a IQueryable method on my repository and returns a IEnumerable containing the enti开发者_如何学Cties. I also need to return the total record count so I can calculate the paging links.
How should I return both the int and IEnumerable from my service method?
- Use a out parameter on the method for the total row count
- Create a separate class that includes the total row count as a property
- Move the paging LINQ query out of the service layer (expose the IQueryable from the repo on the service layer)
- Create a full separate method on the service layer that does a new query just for count.
All of these should work, but which one is the cleanest?
UPDATE: Here is some clarification of the architecture. If this is wrong, then please tell me better way (eg - do the paging in the presentation layer instead of service layer,etc)
Repo layer:
returns IQueryable of DbSet, abstracts the db access from the presentation layer
Service layer:
does a LINQ query on the IQueryable to filter and just get the page items as needed using skip and take and returns a IEnumerable (going to also set to List on return to avoid any DbContext lifetime issues)
Presentation layer:
Call the method on the Service layer (getPagedResults(filters, pageNumber, pageSize))
From the looks of it I will also need to add a separate method to get the total results. Was hopeing to do this all in one call.
I would prefer not to bring back all the records to presentation and then page... seems inefficient.
You can do something like this
public class Repository<TEntity>
{
public IEnumerable<TEntity> GetCollection(Expression<Func<TEntity, bool>> filter,
int pageSize, int pageIndex)
{
return YourDbSet.Where(filter).OrderBy(sortExpression).Skip(pageSize * pageIndex).Take(pageSize);
}
public int Count(Expression<Func<TEntity, bool>> filter)
{
return YourDbSet.Where(filter).Count();
}
}
Then You can write an extension method to use both of these methods
public static Pagination<TEntity> GetPagination<TEntity>(this Repository<TEntity> repository,
Expression<Func<TEntity, bool>> filter, int pageSize, int pageIndex)
{
var entities = repository.GetCollection(filter, pageSize, pageIndex);
var count = repository.Count(filter);
return new Pagination(entities, pageSize, pageIndex + 1, count);
}
This way you can reuse GetCollection
and Count
methods independently.
You can build the where condition dynamically. Take a look at my answer
If the Enumerable
you are returning contains all the items, I would do a ToList()
on it before returning if from the function. (you can then do Count
with no cost on it)
If the function is returning a sub set of the total (using Skip
and take
) I would add a seperate function to get the total count.
精彩评论