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!
Related
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!
Problem: I have millions of rows from database to be processed.
I need to implement a method that will return a "stream"(?) of database rows.
I don't want to load all of them into memory at once.
I was thinking about returning a lazy IEnumerable<Record> and use yield.
The method would handle loading consecutive records using SqlDataReader.
But what will happen when a client will call .Count() on my IEnumerable? Counting all the records would mean a need to fetch them all.
Is there any good modern way to return a stream of objects not storing all of them in memory, just process one by one? My method should return a stream of records.
It seems like Reactive Extensions might solve the problem for me but I have never used it.
Any ideas?
Thanks
First, why reinvent the wheel? Entity Framework makes it easier to do stuff like this and adds all of the abstraction for you. The DbSet<TEntity> on the DbContext object implements IQueryable<TEntity> and IEnumerable<T> so you can:
Execute a Count() (with and without a lamda filter argument) with an extension method when you need to figure out the number of records (or some other aggregate function)
You can loop through them as an IEnumerable which opens a connection and reads 1 record at a time each time the MoveNext method is called from the connection.
If you do want to load everything in memory at once (I understand you don't based on your description) you could call extension method ToList or ToArray.
If you insist on using ADO.NET and manually doing this (I understand with legacy code there is not always a choice to use EF) then opening a data reader from the connection is the best approach. This will read in each next record with each corresponding call to method Read() and this is the least expensive way to go about doing a read of records in the DB.
If you want a Count then I suggest you write a new sql query which returns a count executed on your Database Server using Sql akin to
SELECT COUNT(field) FROM table
as this is best practice. Do not iterate and sum up all of your records from a reader with some custom work around to execute a sum in memory, that would be waste of resources not to mention creating complex code with no benefit.
For count query the db, and return to the user.
On the other hand, you need to implement count only for ICollection, IEnumerable does not require that. just return IEnumerable for iteration on the records.
just notice that you handle correctly the connection to the db.
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
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
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.