Performance issue

Jul 26, 2013 at 8:41 AM
Hello. I found lots of filtering are performed after getting all data from DB. Because the repository layer and business layer all return IEnumerable<>. Does it affect the performance a lot?

However, if not return IEnumerable<>, these layers will become difficult to test.

Is the current design a performance tradeoff to achieve testabilty?

Jul 26, 2013 at 5:34 PM

I believe that usually, when you implement a design pattern to maintain testability, scalability, etc. it's common to experience a small decrement in the application's performance when compared to an implementation without any pattern. How significant this performance decrement will be depends of the context of your application; for most scenarios it should be minimal.

However, in this particular case, I do not understand why returning an IEnumerable<> would impact in the performance of the application at all. Could you elaborate a little more about how this is affecting the performance and what implementation would you prefer to return instead?


Damian Cherubini
Jul 29, 2013 at 1:22 AM

Thanks for your prompt reply.

For functions in data layer, the function ToList() is called before return. For example,
public IEnumerable<Reminder> GetOverdueReminders(int vehicleId, DateTime forDate, int odometer)
            return this.GetDbSet<Reminder>()
                    .Where( r => (r.VehicleId == vehicleId) && (r.DueDate < forDate || r.DueDistance < odometer) && !r.IsFulfilled)
Executing ToList() would cause the query to execute immediately.

In VehicleController.JsonDetails, Take(3) would be carried out against the data in memory. i.e. more than enough data would be retrieved from DB
            var overdue = Using<GetOverdueRemindersForVehicle>()
                .Execute(id, DateTime.UtcNow, vehicle.Odometer ?? 0)
Jul 29, 2013 at 8:26 PM

The following note, took from Chapter 11 - Server-Side Implementation - Implementing the Repository Pattern explains the design decisions took by the team regarding this topic:

The IReminderRepository interface returns collections as IEnumerable<T>, rather than IList<T> or ICollection<T>. This was an intentional design choice to prevent the direct addition of entities to the collections. To create a new reminder, the developer must use the Create method.
In Mileage Stats, the implementation of the IReminderRepository calls ToList before returning the IEnumerable<T>. This is to ensure that the query is executed inside the repository. If ToList was not called, then the repository would return an IQueryable<T> and the database would not be accessed until something iterated over the IQueryable<T> object. The problem with returning an IQueryable<T> is that a developer consuming the API is likely to assume that the query has already executed and that you are working with the results. If you iterate over the query more than once, it will result in multiple calls to the database.
If you specifically want your repository to return queries instead of results, use the IQueryable<T> on the interface in order to make your intention explicit.

I hope this helps in understanding the architecture of the project and the design decisions behind the Mileage Stats implementation.


Damian Cherubini