I'm trying to fetch records from database but in the same call to DB get record count. My methods are async so I'm not sure if this is the right way to do it:
public async Task<IEnumerable<ProductItemViewModel>> GetAsync(int pageIndex, int pageSize)
{
var products = this.Repository.GetAll<Product>().OrderBy(p => p.Price).AsQueryable();
var count = await products.CountAsync();
if (count == 0)
return new List<ProductItemViewModel>();
products = products.ToPaginatedList(pageIndex, pageSize);
var result = await products.ToListAsync();
var viewModels = new List<ProductItemViewModel>();
Mapper.Map(result, viewModels);
return viewModels.AsEnumerable();
}
I think its not so good to await CountAsync() but I'm not sure how to implement it.
Regards.
EDIT:
I apologize for not returning count anywhere, as it looks now that I only count because of that == 0 check, but I will eventually return count with records because I need it for my angular paging directive. Haven't figured it out how I will return (new class vs tuple) so I missed it out and focused on entity framework Count() and entity fetch in single DB call.
I think your code can be optimized to this:
At the end it can be done in just one line:
The
.ProjectTo<ProductItemViewModel>()
will tell AutoMapper's mapping engine to emit a select clause to theIQueryable
that will inform Entity Framework that it only needs to query the properties that you mapped, same as if you manually projected yourIQueryable
to anProductItemViewModel
with aSelect
clause.Oops, I totally missed your return type. I thought you were using the count to display a
TotalResultCount
along with your paginated collection. Since you aren't, cut that out completely.Just drop the
CountAsync()
call, and check theresults.Count
property for zero. That won't be the total number of results you have, but it'll tell you whether it's empty or not.This avoids the extra call to the server, at the cost of that variable's meaning. Read below this line if your pagination supports telling the user agent how many pages there are, for example, but other than that, this code should handle what you're doing here.
This answer holds an incorrect assumption that you needed to know the total result count; I originally read the code incorrectly.
It sounds like what you've got is going to be your best bet.
I don't know of any way in Entity Framework to use T-SQL's
COUNT(*) OVER ()
clause, which is really what it sounds like you're looking for.The only trouble with your approach here is that you'll be running two queries against your server:
That's less efficient than if you could grab them together, but it probably doesn't make a huge difference in a majority of applications. If you're worried about that performance cost, I'd reevaluate indexes you may have, or even think about alternatives to Entity Framework for this.
The fact that this is all
async
doesn't make any difference. Callingawait
againstCountAsync()
is exactly how it's meant to be used.