I have an object IQueryable that represent some query over my db-model.
Now i need to do some validation to that IQeryable and return back the object in that way
private IQuerable<myTableType> ValidateQery ( IQuerable<myTableType> query , string user )
{
return query.Where ( x => db.tblUsers.Where( y => y.User == user && y.Privilege >= x.PrivilegeRequired).Any() )
}
Now what i would like to understand is if the Any() clause is executed immidiatly or if it generate T-SQL that will be merged with previous.
I ask that because i wuold avoid to execute a query against the db in that moment.
Edit :
Thanks for the advice of 'using' clause, it was a fault that i made now (writing this code example) because i am not able to test code now (i have no visual studio on my machine in this moment) but my problem in general was about that situation.
The Any is inside of a lambda in Queryable.Where, and as such is not executed as C# code and is instead translated into an Expression and passed to the query provider when the IQueryable returned from Where is iterated.
On a site node, you're disposing of the context before the IQueryable you return can ever be iterated, so it'll always fail when you do iterate it.
It's part of the query - it's within a Where clause.
So no, it won't be executed immediately. Having said that, you appear to be closing the context that the query uses, so I suspect that by the time it is used, it'll be broken...
Related
This is my first time working with Entity Framework (EF) and I'm trying to learn what exactly executes a query on my database and what doesn't.
This is the code I'm working with. Don't mind the functionality, it isn't important for this question.
using (var db = new Context())
{
//Check if any reviews have been given.
if (combinedReviews.Any())
{
var restaurantsReviewedIds = combinedReviews.Select(rev => rev.RestaurantId);
//(1)
ratedRestaurants = db.Restaurants.Where(rest => restaurantsReviewedIds.Contains(rest.Id))
.DistinctBy(rest => rest.Id)
.ToList();
}
//(2)
var restsClose = db.Restaurants.Where(rest => db.Reviews.Any(rev => rev.RestaurantId == rest.Id))
.OrderBy(rest => rest.Location.Distance(algorithmParams.Location))
.Take(algorithmParams.AmountOfRecommendations);
//(3)
tempList = ratedRestaurants.Union(restsClose).ToList();
var tempListIds = tempList.Select(rest => rest.Id); //Temporary list.
//(4)
restsWithAverage = db.Reviews.Where(rev => tempListIds.Contains(rev.RestaurantId))
.GroupBy(rev => rev.RestaurantId)
.ToList();
}
I have marked each piece of code with numbers, so I'll refer to them with that. Below is what I think is what happens.
This executes a query since I'm calling .ToList() here.
This returns an IQueryable, so this won't execute a query against the database.
This executes the query from (2).
This executes another query since I'm calling .ToList().
How close to the truth am I? Is all of this correct? If this doesn't make sense, could you give an example what executes a query and what doesn't?
I'm sorry for asking so many questions in one question, but I thought I wouldn't need to create so many questions since all of this is about a single topic.
If you don't want to execute a query you can use AsEnumerable.
ToList vs AsEnumerable
ToList – converts an IEnumerable<T> to a List<T>. The advantage of using AsEnumerable vs. ToList is that AsEnumerable does not execute the query. AsEnumerable preserves deferred execution and does not build an often useless intermediate list.
On the other hand, when forced execution of a LINQ query is desired, ToList can be a way to do that.
You could also force execution by putting a For Each loop immediately after the query expression, but by calling ToList or ToArray you cache all the data in a single collection object.
ToLookup and ToDictionary also executing the queries.
Here you can find a list of operators and if they are executing query:
https://msdn.microsoft.com/en-us/library/mt693095.aspx.
Linq query execution is different per query. I recommend reading the following page: https://msdn.microsoft.com/en-us/library/bb738633(v=vs.110).aspx
I use lambda expression to query data, whenever i debug and view memory, memory continuous increase.It can reason make exception "System.OutOfMemoryException".How to clear cache memory whenever finish execute lambda expression?
public override IQueryable<TableA> GetList(Func<TableA, bool> conditon, bool isNoTracking = false)
{
var result = Context.TableA
.Join(Context.TableB.AsNoTracking(), x => x.TYU_URICOMCODE, y => y.MACS_KOKYAKU_CODE, CreateOrder)
.Where(conditon).AsQueryable();
return result;
}
I have a few suspicions:
Your CreateOrder side-effect is doing something that is using up memory. Remember it's running per-row returned.
You're inadvertently loading all rows from the database, then using the in-memory LINQ methods to join/filter it.
Note that in the database-specific flavour of LINQ, .Where() returns a WhereIterator, which is already queryable, so building a new queryable is unnecessary, and will also be doing memory allocations. If you're having to call .AsQueryable() to get it to compile, then you're almost certainly falling foul of suspicion #2 above.
Will LINQ use defered execution when we map the result to an object?
var x = from rcrd in DBContext.FooTable
select new Model.BOFoo()
{ Bar = rcrd.Bar };
The above code map rcrd to Model.BOFoo object. Will this mapping cause LINQ to fetch the actual data from the database? Or will it wait until I call x.ToList()?
I'd answer yes. If I don't miss any information about this, LINQ will still use deferred execution even if we map the result to object. The object initialization will also be deferred.
Unless your Linq query includes a method that executes the query, then no, it will not execute and will be deferred.
Examples of methods that execute the query include First(), FirstOrDefault(), ToList(), ToArray, etc..
select is not such a method, not even select new.
I always find it useful to think of the code as it would be in a method chain:
DBContext.FooTable
.Select(rcrd=>new Model.BOFoo{Bar=rcrd.Bar});
Here it is easier to visualize the deferred execution as you are only passing a function into the Select that will be evaluated as needed. The new is merely a part of that function.
So, as har07 and Erik already mentioned, if it is a deferred execution method, then it will remain that way unless forced via another method such as ToList
If I run against dlinq, for example
var custq = data.StoreDBHelper.DataContext.Customers as IEnumerable <Data.SO.Customer>;
I Thought it was not much of a difference against running:
var custq = data.StoreDBHelper.DataContext.Customers as IQueryable <Data.SO.Customer>;
As, IQueryable inherits from IEnumerable.
But I discovered the following, if you call:
custq.Sum()
then the program will process this as you called .toList() it you use the 'as IEnumerable'
because the memory on the progam raised to the same level, when i tried, custq.ToList.Sum()
but not on the 'as IQueryable' (because the issue then running on sql server) and did not affect the memory usage of the program.
My question is simply this, should you not use 'as IEnumerable' on Dlinq? But 'as IQueryable' as an general rule? I know that if you are running standard iterations, it gets the same result, between 'as IEnumerable'and 'as IQueryable'.
But is it just the summary functions and delegate expressions in where statement that there will be a difference - or will you in general get better performance if you use 'as IQueryable'? (for standard iteration and filter functions on DLinq entities)
Thanks !
Well, depends on what you want to do...
Casting it as IEnumerable will return an object you can enumerate... and nothing more.
So yes, if you call Count on an IEnumerable, then you enumerate the list (so you actually perform your Select query) and count each iteration.
On the other hand, if you keep an IQueryable, then you may enumerate it, but you could also perform database operations like Were, OrderBy or count. Then this will delay execution of the query and eventually modify it before running it.
Calling OrderBy on an enumerable browse all results and order them in memory. Calling OrderBy on a queryable simply adds ORDER BY at the end of your SQL and let database do the ordering.
In general, it is better to keep it as an IQueryable, yes... Unless you want to count them by actually browsing them (instead of doing a SELECT COUNT(*)...)
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