I'm working with entity framework with POCO objects and I've got LazyLoading turned on.
If i'm working with a collection associated with an object, when is the collection fully loaded and in what circumstances?
If I call each of these
Order.OrderItems.Count()
Order.OrderItems.Any(x => x.StatusId = aValue)
Order.OrderItems.All(x => x.StatusId = aValue)
Do any of these guarantee the complete loading of the OrderItems collection?
At points in the code we are calling
Order.Include(“OrderItems”)
when querying or
context.LoadProperty(order, “OrderItems”)
after querying
But I’ve realised sometimes this isn’t always happening – and I want to know the consequences of this not occurring. I think I’ve got a bit of a knowledge gap with it
Linq methods don't generally load your data until you either foreach over their result, or append a ToList, ToArray, etc. This is how the Linq to Entities provider can allow you to chain methods and only build a query over the final structure.
If a method returns an IQueryable or IEnumerable, you can be pretty sure that Linq won't load the data at that point.
But:
Order.OrderItems.Count()
Order.OrderItems.Any(x => x.StatusId = aValue)
Order.OrderItems.All(x => x.StatusId = aValue)
For an outer-most query, if Linq must return a boolean value or an integer then it must run your query immediately. But things get a little more complicated for nested queries, since they won't be evaluated until the outer query gets evaluated.
As for:
Order.Include("OrderItems")
I believe an Include won't resolve a query on its own. You use it to piggyback additional data when you're making another query.
Linq in general
If you want to know (generally) how Linq works, you can check out this set of articles:
http://msmvps.com/blogs/jon_skeet/archive/tags/Edulinq/default.aspx
That will give you an idea of when an IEnumerable can be deferred, and when it must be evaluated. It won't tell you everything about the Linq to Entities provider, but a good portion of the knowledge will transfer.
Order.OrderItems.Any(x => x.StatusId = aValue)
Order.OrderItems.All(x => x.StatusId = aValue)
are queries.
These queries are executed when you call .ToList() (or some other iterator to materialize it into objects). If you use .Include then included property will be populated (query will contain join for that table) when you execute query. Using Any or All (or any filter extension like Where) only adds where condition (which can be from another table), but it does not put OrderItems into sql select, so they will not be loaded unless you use .Include.
--
Not related to your question, but if you are fresh with this, and you have paging, remember to add Skip and Take to your query before calling ToList (executing query), I have seen people calling ToList very early and reading whole table to memory before doing paging.
Related
This code causes a NotSupportedException.
var detailList = context.Details.Where(x => x.GetType().GetProperty("Code").GetValue(x,null).ToString() == "00101").ToList();
But this code works.
var detailList = context.Details.AsEnumerable().Where(x => x.GetType().GetProperty("Code").GetValue(x,null).ToString() == "00101").ToList();
MSDN says:
- AsEnumerable() Returns the input typed as IEnumerable
- DbSet Is an IEnumerable
So why we need to use AsEnumerable() method?
DbSet is also IQueryable.
IQueryable has its own set of LINQ extension methods that translate expression trees into SQL, and do not support reflection.
By calling AsEnumerable(), you change the compile-time type of the expression to IEnumerable<T>, forcing the extension methods to bind to the standard LINQ ones.
If you prefer to run your query on the server, you should build an expression tree instead of using reflection.
The first query attempts to have the query provider translate the query into SQL and execute it against the database. It fails to create a valid database query, so it fails with the error mentioned.
Using AsEnumerable types the query as an IEnumerable<T>, rather than an IQueryable<T>, statically, and as such ends up calling the LINQ to objects version of the query methods, pulling the entire table into memory and then performing all of the operations within the application.
When you're querying an IQueryable<T>, your method gets translated via an Expression Tree into SQL. AsEnumerable to change the compile time type to IEnumerable<T> and to bring all the entities from your database into memory, where you can query them via reflection via LINQ to Objects.
It seems to me that Linq can only -query- a given data source, that is, it browses through it and returns stuff from it as necessary, but doesn't change anything. However, the wording in some of the answers I found on the matter are making me doubt this understanding. Is my understanding correct in all circumstances? Can a linq query -ever- change the content of the data source it is associated to?
Can a linq query -ever- change the content of the data source it is associated to?
Yes, though this is a bad idea.
LINQ queries (at least with LINQ to Objects) work by using delegates for the filter or mapping operations. In general, these shouldn't ever cause side effects, but that doesn't mean that they couldn't do so if you forced them to. The actual LINQ methods won't change the data, but they work via delegates that are just code you provide, which means that code could do anything.
Note that this would, in general, be a bad idea.
For example, say you were doing a query over a collection of Person instances:
var results = people.Where(p => p.Name == "Foo")
.Select(p =>
{
// This is evil, don't do it!
p.Name = "Bar";
return p;
});
That being said, this is unlikely to work with LINQ against an IQueryable<T>. In that case, the lambda you provide will be converted into an Expression, which will in turn need to be translated by the provider into some other form (ie: Entity Framework converts this to SQL). As such, you would only be able to create side effects if the provider was written in a way that this would translate into a meaningful form, which is unlikely to be the case.
I have a property called Total that is derived from other values on my data object. When I try to use this property in an order by statement in linq to sql I get: The member '...' has no supported translation to SQL. Which makes sense but is there a work around for this scenario? Thanks!
You could invoke the query and than do your OrderBy() clause.
var items = context.Tables.ToList().OrderBy(x=>x.Total);
You can do this since after you invoke .ToList() you will be using linq to objects.
As Broken mentions this might not work in all cases, another possible solution would be to reproduce your total calculation in your .Select()
note, my syntax might be off a bit, dont have VS with me :)
var items = context.Tables.Select(t=> new {t.Item1, Total=(t.Price + t.Tax)})
.OrderBy(t=>t.Total);
Now granted with this type of projection you wont end up with a Table any more but might be an option.
The project I'm working currently on has a way to define a filter on objects from a database.
This filter is a pretty straightforward class containing criteria that will be combined to produce a SQL where clause.
The goal now is to use this class to filter .Net objects as well. So for example the filter might specify that the title property of the object that it is applied to must contain some user-defined string.
What are ways to approach this problem? What should the filter return instead of the sql where-clause and how can it be applied to the object? I've been think about this for hours and don´t yet have even a slight idea how to solve this. Been thinking about reflection, dynamic code execution, building expressions but still haven´t found a starting point.
It depends on what all the use-cases are :)
If your DB code could use LINQ, then I might consider returning an Expression<Func<YourEntity,bool>>, as this can be applied via .Where to both DB-based LINQ and LINQ-to-Objects - in the latter case simply by calling:
var filtered = original.AsQueryable().Where(filter);
(DB code is typically already queryable, so no AsQueryable is needed).
One bad thing about this is that there is no guarantee that a particular query expression will work on every LINQ provider.
Alternatively, you would have to write either your own basic query language, or a basic tree-structure. And then write code to translate to both property-reflection and SQL. Lots of work.
One final thought is to just have two different query results, and keep the two thigs separate. So one SQL, one Predicate<T> or similar. There is a risk of them being out of sync, though.
If you want to do it a bit like the dynamically created SQL where clause, you could use Dynamic LINQ to achieve similar effects.
What is the quickest way to find out which .net framework linq methods (e.g .IEnumerable linq methods) are implemented using deferred execution vs. which are not implemented using deferred execution.
While coding many times, I wonder if this one will be executed right way. The only way to find out is go to MSDN documentation to make sure. Would there be any quicker way, any directory, any list somewhere on the web, any cheat sheet, any other trick up your sleeve that you can share? If yes, please do so. This will help many linq noobs (like me) to make fewer mistakes. The only other option is to check documentation until one have used them enough to remember (which is hard for me, I tend not to remember "anything" which is documented somewhere and can be looked up :D).
Generally methods that return a sequence use deferred execution:
IEnumerable<X> ---> Select ---> IEnumerable<Y>
and methods that return a single object doesn't:
IEnumerable<X> ---> First ---> Y
So, methods like Where, Select, Take, Skip, GroupBy and OrderBy use deferred execution because they can, while methods like First, Single, ToList and ToArray don't because they can't.
There are also two types of deferred execution. For example the Select method will only get one item at a time when it's asked to produce an item, while the OrderBy method will have to consume the entire source when asked to return the first item. So, if you chain an OrderBy after a Select, the execution will be deferred until you get the first item, but then the OrderBy will ask the Select for all the items.
The guidelines I use:
Always assume any API that returns IEnumerable<T> or IQueryable<T> can and probably will use deferred execution. If you're consuming such an API, and need to iterate through the results more than once (e.g. to get a Count), then convert to a collection before doing so (usually by calling the .ToList() extension method.
If you're exposing an enumeration, always expose it as a collection (ICollection<T> or IList<T>) if that is what your clients will normally use. For example, a data access layer will often return a collection of domain objects. Only expose IEnumerable<T> if deferred execution is a reasonable option for the API you're exposing.
Actually, there's more; in addition you need to consider buffered vs non-buffered. OrderBy can be deferred, but when iterated must consume the entire stream.
In general, anything in LINQ that returns IEnumerable tends to be deferred - while Min etc (which return values) are not deferred. The buffering (vs not) can usually be reasoned, but frankly reflector is a pretty quick way of finding out for sure. But note that often this is an implementation detail anyway.
For actual "deferred execution", you want methods that work on an IQueryable. Method chains based on an IQueryable work to build an expression tree representing your query. Only when you call a method that takes the IQueryable and produces a concrete or IEnumerable result (ToList() and similar, AsEnumerable(), etc) is the tree evaluated by the Linq provider (Linq2Objects is built into the Framework, as is Linq2SQL and now the MSEF; other ORMs and persistence-layer frameworks also offer Linq providers) and the actual result returned. Any IEnumerable class in the framework can be cast to an IQueryable using the AsQueryable() extension method, and Linq providers that will translate the expression tree, like ORMs, will provide an AsQueryable() as a jump-off point for a linq query against their data.
Even against an IEnumerable, some of the Linq methods are "lazy". Because the beauty of an IEnumerable is that you don't have to know about all of it, only the current element and whether there's another, Linq methods that act on an IEnumerable often return an iterator class that spits out an object from its source whenever methods later in the chain ask for one. Any operation that doesn't require knowledge of the entire set can be lazily evaluated (Select and Where are two big ones; there are others). Ones that do require knowing the entire collection (sorting via OrderBy, grouping with GroupBy, and aggregates like Min and Max) will slurp their entire source enumerable into a List or Array and work on it, forcing evaluation of all elements through all higher nodes. Generally, you want these to come late in a method chain if you can help it.
Here's a summary of different ways you can know if your query will be deferred or not:
If you're using query expression syntax instead of query method syntax, then it will be deferred.
If you're using query method syntax, it MIGHT be deferred depending on what it returns.
Hover over the var key word (if that's what you're using as the type for the variable used to store the query). If it says IEnumerable<T> then it'll be deferred.
Try to iterate over the query using a foreach. If you get an error saying it cannot iterate over your variable because it does not support GetEnumerator(), you know the query is not deferred.
Source: Essential Linq
If you cast the collection to an IQueryable using .AsQueryable(), your LINQ calls will use the deferred execution.
See here: Using IQueryable with Linq