IEnumerable vs ToList while directly iterating in view - c#

If I only have to use that result one time i.e. in iterating and displaying in view. I generally do 1st one, is it wiser?
IEnumerable<model> result = _someService.GetValues();
return View(result);
OR
IList<model> result = _someService.GetValues().ToList();
return View(result);
I checked in profiler and db is queried only once for that data using EF6.
To clear its a plain SELECT and both has data and there is no adjacent list to kick in lazy loading.
Note: I know IEnumerable has one method GetEnumerator which executes everytime its called it executes for data whereas ToList() executes only once.

See Programmers.SE: Why should I use List<T> over IEnumerable<T>?:
There are times when doing a ToList() on your linq queries can be important to ensure your queries execute at the time and in the order that you expect them to.
This is exactly the case here.
If _someService.GetValues() returns an IEnumerable<model> which is an Entity Framework query through deferred execution, calling ToList() in your controller will execute the query there: in your controller, where you can handle the exceptions that may occur. For example a query timeout.
If you don't call .ToList(), that same exception will be thrown instead at #foreach (var item in Model) in your view. You don't want that.
Also, if you use lazy loading, the context will be disposed by the time the query result end up in your view and throw an exception again, so in that case you'll have to materialize the query results in your controller by calling .ToList().
People get all high up in a tree when it comes to IEnumerable<T> versus IList<T>. They are generally parroting each other from some general advice (found here, amongst others), but they do not understand that that advice is for API design. You are not designing an API, you are implementing an application with very specific requirements: the view may never throw an exception. In order to fulfill that requirement, you must execute your queries in your controller, hence call .ToList() there.
The user asking the question linked above is right in the comment they posted:
all queries should be executed so that the model is done and loaded ready for the view. I.e. the view should receive everything and not be querying the database.
Razor rendering your model to your view may not have any side-effects. Executing a query is a side-effect, so that may not happen while rendering your view.
Even when calling .ToList() in your controller, your #model directive in the view can and should still be of IEnumerable<T> though!

Related

Getting RowCount For IQueryable not IQueryable<T>

Long story short, we have a C# WebApi that provides mapped instances from our DAL into DTOS.
Each controller exposes a IEnumerable<T> Get()
I have a test that finds all the controllers, and call this get method.
This flushes out any mapping errors that only occur on execution.
A while I noticed that to be sure you had to actually execute the enumeration otherwise the the mapping never takes place.
So I have this code
if (results is IEnumerable enumerable)
{
var counter = enumerable.Cast<object>().Count();
Trace.Write($"{counter} results found.");
}
This executes the cast (which invokes the mapping) and gives me a count for output reasons.
This worked until the result set got massive - it nows just times out.
Most of my IEnumerables are actually IQueryable underneath
I need a way to Take(10) on an IQueryable that can work on reflected data/executed types. This will let the mapping work but on a smaller data set.
Help!

Entity Framework - Lazy Loading working even with ToList()

First of all, I am using EF 6.0 with Code First approach.
My context Configuration is set to Enable "Proxy Creation" and "Lazy Loading".
My question is:
Does the lazy loading work with results of a method that returns IEnumerable (and not IQueryable)?
I think the code below is more explanatory:
public void Test()
{
var company = GetCompanies().FirstOrDefault();
if (company.Employees.Count() > 0)
{
//I got here without errors!
}
}
public IEnumerable<Company> GetCompanies()
{
var company = context.Companies.ToList();
//Note that I did not Include the Employee (child table)
return company;
}
Note comment where I say that: "I got here without errors!". It means that lazy loading is working even after ToList() call. I thought that after converting IQueryable to List or IEnumerable the EF would lose the capability of doing lazy loading.
I have noted that the Proxy still enabled for the entities that are returned by GetCompanies method (in debbug mode I can see that ugly hash like: System.Data.Entity.DynamicProxies.Company_7035BEA374959AC1...).
The lazy loading works even when calling it on different DLL. Is this correct? I mean, can a different DLL make subsequent calls in my database even if my method returns an IEnumerable (and not IQueryable)?
Any clarification will be greatly appreciated.
Note that comment that I say: "I got here without errors!". It means
that lazy loading is working even after ToList() call.
That's the whole point of lazy-loading: you can get entities from the DB when they are required (i.e. when you access to the property), not only when you execute the query for the first time (i.e. your call to .ToList()).
The lazy loading works even calling it on different DLL. Is this
correct? I mean, can a different DLL made subsequent calls in my
database even if my method return an IEnumerable (and not IQueriable)?
Yes it's correct, but be careful, if you dispose your context, lazy loading won't work (it'll throw an ObjectDisposedException).
Also, while your code will work, you might have performance issues because of the number of SQL requests generated.
Side note: personally I recommend to not use lazy-loading. See https://stackoverflow.com/a/21379510/870604

LINQ .FromCache().ToList()?

When using .FromCache() on an IQueryable result set, should I additionally call .ToList(), or can I just return the IEnumerable<> returned by the materialized query with FromCache?
I am assuming you are using a derivative of the code from http://petemontgomery.wordpress.com/2008/08/07/caching-the-results-of-linq-queries/ . If you look at the FromCache implementation, you will see the that the query.ToList() is already called. This means that the evaluated list is what is cached. So,
You do NOT need to call ToList()
That depends entirely on what you want to do with it. If you're just going to foreach over it once then you may as well just leave it as an IEnumerable. There's no need to build up a list just to discard it right away.
If you plan to iterate over it multiple times it's probably best to ToList it, so that you're not accessing the underlying IQueryable multiple times. You should also ToList it if it's possible for the underlying query to change over time and you don't want those changes to be reflected in your query.
If you are likely to not need to iterate all of the items (you may end up stopping after the first item, or half way, or something like that) then it's probably best to leave it as an IEnumerable to potentially avoid even fetching some amount of data in the first place.
If the method has no idea how it's going to be used, and it's just a helper method that will be used by not-yet-written code, then consider returning IEnumerable. The caller can call ToList on it if they have a compelling reason to turn it into a list.
For me, as a general rule, I leave such queries as IEnumerable unless I have some compelling reason to make it a List.

Filtering IQueryable<T> returns wrong result

I have just run into quite surprising problem.
The case is simple: return all entities that are currently active, which means: filter all result returned by GetAll() method according to their Boolean Active property
public IQueryable<T> GetAllActive()
{
return implementation.GetAll().Where(a => ((IDeactivable)a).Active);
}
where GetAll() method of implementation object is defined as:
public IQueryable<T> GetAll();
The problem is, that GetAllActive() returns all the records, regardless of value of their Active property, just like there is no Where clause.
What could be the reason for it?
Note: The code is simplified, T type is checked to implement the IDeactivable interface. Also no exception is thrown during at runtime.
Edit: IQueryable returned by implementation object comes from NHibernate
Edit2: I have used following code to check the actual values for the entities (besides using VS Debugger):
foreach (var a in active) { //active -> filtered IQueryable before return
_logger.Warn(a.Id);
_logger.Warn(((IDeactivable)a).Active);
}
the result was:
11/30/2011 18:10:00 WARN xxx.Repository`1.GetAllActive: 70db43fa-2361-4c1f-a8e5-9fab012b5a2b
11/30/2011 18:10:01 WARN xxx.Repository`1.GetAllActive: False
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: 5493c9bb-ec6e-4690-b5d6-9fab012b5b16
11/30/2011 18:10:02 WARN xxx.Repository`1.GetAllActive: True
When you return an IQueryable<T>, you are not actually returning a result set. What you are returning is an object that can be queried.
Execution of the .Where() method is deferred until you (or someone calling your method) actually compels execution of the Linq chain. This is what makes it possible for downstream clients to apply their additional Linq methods to the result, and still get lazy evaluation for the entire Linq chain.
So when you say that the IQueryable<T> is returning all records, you're probably looking at the result in the debugger, and it's showing you the original data set without the filtering (since the .Where() hasn't executed yet).
The reason casting to IEnumerable works is because it triggers execution of the Linq command chain, and the result is a bonafide list, rather than an object that can be queried. Calling ToList() or ToArray() will also trigger execution.
In short, the only way you can be sure you're seeing the correct result from your Linq methods during your testing process is to force execution of the Linq chain:
foreach(var record in GetAllActive.ToList())
{
// Display each record
}
For a little flavor of how this works, see Working with Deferred Execution. It contains an example showing how you can actually get into trouble returning an IQueryable from a using block, because the IQueryable object gets disposed before the query executes.
I have tried several different approaches and I finally I have found a part of my code not tested yet. It turned out that LINQ Queries to NHibernate caused some issues when using Where clause, that I have not noticed before.
Eventually, I figured out, that I am using a wrong version of LINQ to NHibernate QueryProvider (not the one included in NH 3.0) and that is a known issue. Now that I have get rid of it, everything works fine. THANK YOU FOR YOUR HELP, GUYS! You pointed me out to the right direction.
Mentioned issue is described in following thread:
Problem with linq query

Why use AsQueryable() instead of List()?

I'm getting into using the Repository Pattern for data access with the Entity Framework and LINQ as the underpinning of implementation of the non-Test Repository. Most samples I see return AsQueryable() when the call returns N records instead of List<T>. What is the advantage of doing this?
AsQueryable just creates a query, the instructions needed to get a list. You can make futher changes to the query later such as adding new Where clauses that get sent all the way down to the database level.
AsList returns an actual list with all the items in memory. If you add a new Where cluse to it, you don't get the fast filtering the database provides. Instead you get all the information in the list and then filter out what you don't need in the application.
So basically it comes down to waiting until the last possible momment before committing yourself.
Returning IQueryable<T> has the advantage, that the execution is defferer until you really start enumerating the result and you can compose the query with other queries and still get server side execution.
The problem is that you cannot control the lifetime of the database context in this method - you need an open context and must ensure that it stays open until the query gets executed. And then you must ensure that the context will be disposed. If you return the result as a List<T>, T[], or something similar, you loose deffered execution and server side execution of composed queries, but you win control over the lifetime of the database context.
What fits best, of course, depends on the actual requirements. It's another question without a single truth.
AsQueryable is an extension method for IEnumerable<T> that could do two things:
If the IEnumerable<T> implements IQueryable<T> justs casts, doing nothing.
Otherwise creates a 'fake' IEnumerable<T> (EnumerableQuery<T>) that implements every method compiling the lambdas and calling to Enumerable extension methods.
So in most of the cases using AsQueryable is useless, unless u are forced to pass a IQueryable to a method and u have a IEnumerable instead, it's a hack.
NOTE: AsQueryable is a hack, IQueryable of course is not!
Returning IQueryable<T> will defer execution of the query until its results are actually used. Until then, you can also perform additional database query operations on the IQueryable<T>; on a List you're restricted to generally less-efficient in-memory operations.
IQueryable: This is kind of deferred execution - lazy loading so your query is evaluated and hit to database. If we add any additional clause it will hit the Db with the required query with filters.
IEnumerable: Is eager loading thus records will be loaded first in-memory operation and then the operation will be performed.
So depending on use case like while paging on a huge number of records we should use IQueryable<T>, if short operation and doesn't create huge memory storage use IEnumerable.

Categories