Reputation: 577
We have developed an application in MVC, using entity framework and the repository pattern. When a user logs in they see a dashboard with several counts of shifts depending on their status. See below:
In the controller we populate the ViewModel using the following line:
viewModel.shiftsInProgress = _shiftDateService.GetShiftDatesByStatusID(72).Count();
This links to the following method:
public IList<ShiftDate> GetShiftDatesByStatusID(int statusID)
{
return _UoW.ShiftDates.Get(s => s.shiftDateStatusID == statusID)
.OrderByDescending(s => s.shiftID).ToList();
}
This method is also used to pull out the list of shifts by status in another view.
Our Unit of Work (_UOW) is mapped to a generic repository which contains 2 get methods:
public IList<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
return dbSet.SqlQuery(query, parameters).ToList();
}
I am looking some advice on whether or not this is best practice, the queries on the dashboard where the counts are being pulled out are starting to slow the application down. I'm thinking this is because we are pulling back an ilist for each count on the dashboard and then using the Count() method inside the controller for each.
Should I do the following?
Add another method to the generic repository, IEnumerable GetAll(); - then use this to get a count of the records.
Use the method 'GetWithRawSql' and then use SQL to get a count.
Something else? Like below:
Would I be better removing the 'Shifts Completed' count then bring back an IList of all incomplete shifts to the controller. Inside the controller then use linq to query by status and use the count() method. i.e.
ilist<shiftdate> allIncompleteShifts = _shiftService.GetIncompleteShifts.ToList();
ViewModel.InProgress = allIncompleteShifts.Where(s => s.status ==72).Count();
ViewModel.Submitted = allIncompleteShifts.Where(s => s.status ==73).Count();
How would this affect performance
Upvotes: 4
Views: 7432
Reputation: 2929
You have several options here. One commonly used approach is, to return an IQueryable<TEntity>
from your repository instead of returning an IList<TEntity>
.
With this approach, the queries are executed on the database and not in-memory. This includes filtering, ordering, etc. Also the Count()
will be translated to the according SQL and executed on the database.
Another approach would be to create a less-generic repository which also includes specific queries.
There is a discussion whether you should expose an IQueryable<TEntity>
in this question. The conclusio is: It depends, whether you want to give the users of the repository more flexibility with IQueryable<TEntity>
. You must then keep in mind that users can now perform queries which you might have not intended. You can find more details on this in the given link.
Upvotes: 4