I have a query that looks like this
var query = db.Customer
.Include(c => c.Address)
.Where(c => c.Address.Id > 10)
.ToList();
when i do this instead
var query = db.Customer
.Where(c => c.Address.Id > 10)
.ToList();
db.Address
.Where(a => a.Id > 10)
.Load();
I get the same result as far as I see.
My question is: is there any difference between what these two queries return and is one preferred over the other?
var query = db.Customer
.Include(c => c.Address)
.Where(c => c.Address.Id > 10)
.ToList();
On above query where it brings all the related data using single database trip.
var query = db.Customer
.Where(c => c.Address.Id > 10)
.ToList();
db.Address
.Where(a => a.Id > 10)
.Load();
Here it uses 2 database trips to bring the data.
Load :
There are several scenarios where you may want to load entities from
the database into the context without immediately doing anything with
those entities. A good example of this is loading entities for data
binding as described in Local Data. One common way to do this is to
write a LINQ query and then call ToList on it, only to immediately
discard the created list. The Load extension method works just like
ToList except that it avoids the creation of the list altogether.
Note : We cannot say which one is better.Most of the time we use eager loading method (Include).It is nice and simple.But sometimes it is slow.So you need to decide which one to use according to your data size and etc.
Related
I am attempting to get a list of Order Ids from a EF linq query. The sql query is returning back quickly but I think the EF framework is trying to create the full entity. I only want the ID of the order. It seems that it creates the whole entity and then it parses it out to only the id. Which seems to be a complete waste of resources.
Orders are a complex object that includes lots of child entitys. I dont need anything but the Ids of the orders in the list. Orders are organized into OrderCollection which is a many to many relationship.
The basic query in English is get the order ids in the specified order collection and have a cart date newer then the date specified and only send the specified page (skip and take).
example:
_repo.Orders.Where(o => o.OrderCollection.Any(r => r.Id == RoutingRuleId)).ToList()
.Where(o => o.OrderDate >= StartDateTime)
.OrderBy(x => x.OrderDate )
.Skip(RecordsToSkipCount)
.Take(BatchSize).Select(x => new { x.Id }).ToArray();
The sql runs in just 102ms for this in debug mode. But afterwards I see the memory go to up 4GB before failing. The batchsize is only 100. Its like it grabbing everything.
I tried moving the select around but that failed also or gave syntax errors or poor performance in running the sql (SQL taking 16 seconds).
Example
_repo.Orders.Select(x => new { x.Id, x.OrderCollection, x.OrderDate})
.Where(o => o.OrderCollection.Any(r => r.Id == RoutingRuleId)).ToList()
.Where(o => o.OrderDate >= StartDateTime)
.OrderBy(x => x.OrderDate )
.Skip(RecordsToSkipCount)
.Take(BatchSize).Select(x => new { x.Id }).ToArray();
The database has millions of records.
What you have is roughly;
List<Order> list = _repo.Orders
.Where(o => o.OrderCollection.Any(r => r.Id == RoutingRuleId))
.ToList();
list.Where(o => o.OrderDate >= StartDateTime)
.OrderBy(x => x.OrderDate )
.Skip(RecordsToSkipCount)
.Take(BatchSize)
.Select(x => new { x.Id })
.ToArray();
That first .ToList is forcing EF Core to load every order with a matching routing rule into memory. The rest of the expression is then using IEnumerable extension methods to process those results.
I think you want to rearrange that to;
IQueryable<Order> query = _repo.Orders
.Where(o => o.OrderCollection.Any(r => r.Id == RoutingRuleId)
&& o.OrderDate >= StartDateTime)
.OrderBy(x => x.OrderDate )
.Skip(RecordsToSkipCount)
.Take(BatchSize)
.Select(x => new { x.Id });
query.ToArray();
Creating an IQueryable doesn't trigger EF Core to execute any SQL. An IQueryable is just a description of the query you would like to run. Then it's the .ToArray method that will finally cause EF Core to compile and execute an sql statement.
The Problem
I have a LINQ query (against Entity Framework) that use Include to include some navigation properties. One of those properties uses ThenInclude to include its own property collection. When I run the query, the first level properties are included on the primary object but the sub-collection (the one using ThenInclude) is always empty.
However, if I change the query to use Fluent API form, the query works and the sub-collection is actually included. Why does this work for the Fluent form and not the normal LINQ query?
Example
//FAIL - This returns Benefits but Benefits.Dates.Count = 0 on all Benefits
var list1 = (from s in _context.Subscribers
.Include(s => s.Dates)
.Include(s => s.Benefits)
.ThenInclude(b => b.Dates)
where s.Id == 13643
select new { benefits = s.Benefits }).ToList();
//SUCCESS - This returns Benefits and Benefits.Dates.Count is > 0 on the ones with Dates
var list2 = _context.Subscribers
.Include(s => s.Dates)
.Include(s => s.Benefits)
.ThenInclude(b => b.Dates)
.Where(s => s.Id == 13643)
.Select(s => new { benefits = s.Benefits}).ToList();
Am I mistaken that these queries should give the same output?
Update
I just tried manually linking things using LINQ and I am able to get Benefit dates included -- granted, its not apples to apples as the resulting set is different, but the point is that Include(b => b.Dates) seems to work in this case.
var list3 = (from s in _context.Subscribers.Include(s => s.Dates)
join b in _context.Benefits.Include(b => b.Dates) on s.Id equals b.SubscriberId
select new {benefits = b}).ToList();
I'm beginning to wonder if ThenInclude() may be a little more restrictive in where/when it can be used?
Update 2
I just noticed a warning in my Debug Output window that led me to this link about ignored includes. This seems to be on the right track as the Debug Output clearly indicates that these includes are being ignored.
What doesn't make sense, though, is that I'm actually selecting to anonymous in both examples and only one of them seems to ignore the includes. Why one and not the other?
This is just a guess: since You have Datas, in both Subscribers and Benefits, there is a chance that you are not querying the correct model/entity... you can try confirming the entity type like below (assuming Benefit is your Entity type).
var list1 = (from s in _context.Subscribers
.Include(s => s.Dates)
.Include(s => s.Benefits)
.ThenInclude(b => (b as Benefit).Dates)
where s.Id == 13643
select new { benefits = s.Benefits }).ToList();
var list2 = _context.Subscribers
.Include(s => s.Dates)
.Include(s => s.Benefits)
.ThenInclude(b => (b as Benefit).Dates) // <-- I suggest renaming s to b
.Where(s => s.Id == 13643)
.Select(s => new { benefits = s.Benefits}).ToList();
I need to append the results of one LINQ To SQL query to another on the database server side without reordering rows.
I need all errored orders first, then the pending orders.
var error = database.Orders.
Where(o => o.Status == XOrderStatus.Error).
OrderByDescending(o => o.Id);
var pending = database.Orders.
Where(o => o.Status == XOrderStatus.PendingReview).
OrderByDescending(o => o.Id);
var r = error.OrderedUnion(pending);
How I can implement the OrderedUnion() method? Concat, Union and Distinct methods completely eliminate OrderByDescending call (by design).
I know it is possible to do with two ToArray() calls, but I am interested having this done at the database level.
You can concatente them together and then order by a column that seperates the order groups. so for instance in an SQL Query you would do this:
ORDER BY XOrderStatus, Id
and that would order by ID but with the two OrderStatuses grouped.
I don't know linq to sql (sorry!) but a quick Google mentioned this may work:
.Orderby(o => o.XOrderStatus).ThenBy(o => o.Id)
Original Source:
Multiple "order by" in LINQ
I found much better solution:
var all = database.Orders.
Where(o =>
o.Status == XOrderStatus.Error ||
o.Status == XOrderStatus.PendingReview).
OrderBy(o => o.Status == XOrderStatus.Error ? 0 : 1).
ThenByDescending(o => o.Id).
ToArray();
I have 2 LINQ Queries here, i just want to know which of these query is proper and fast to use.
Sample I
var GetUSer = (from UserItem in dbs.users
where UserItem.UserID == UserID
select new User(UserItem))
.OrderBy(item => item.FirstName)
.Skip(0)
.Take(10)
.ToList();
Sample II
var GetUSer = (from UserITem in dbs.user
.Where(item => item.UserID == UserID)
.OrderBy(item => item.FirstName)
.Skip(0)
.Take(10)
.AsEnumerable()
select new User(UserItem)).ToList();
Although they are both working well, i just want to know which is the best.
The Second one is better, the first 1 does a select then does filtering, meaning it has to get the data from the database first to turn it into a User object, then it filters.
The second one will do the query on the DB side, then turn it into a User object
The first one can be fixed by moving the select till just before the ToList()
Between those two, I would prefer the first (for readability, you'd need to switch some things around if you want the whole query to execute in the database). If they both work, it's up to you though.
Personally, I don't like mixing query syntax with lambda syntax if I don't have to, and I prefer lambda. I would write it something like:
var GetUsers = db.user
.Where(u => u.UserID == UserID)
.OrderBy(u => u.FirstName)
.Take(10)
.Select(u => new User(u))
.ToList();
This uses a single syntax, queries as much as possible in the database, and leaves out any superfluous calls.
I need to order the articles stored in a database by descending publication date and then take the first 20 records after the article with Id == 100.
This is what I would like to do with Linq:
IQueryable<Article> articles =
db.Articles
.OrderByDescending(a => a.PublicationDate)
.SkipWhile(a => a.Id != 100)
.Take(20);
However, this generates a NotSupportedException because SkipWhile is not supported in Linq to Sql (see here).
A possible solution is to execute the query and then apply SkipWhile using Linq to Object:
IEnumerable<ArticleDescriptor> articles =
db.Articles
.OrderByDescending(a => a.PublicationDate)
.ToList()
.SkipWhile(a => a.Article.Id != 100)
.Take(20);
But this means I need to load the whole ordered list into memory first and then take 20 articles after the one with Id == 100.
Is there a way to avoid this huge memory consumption?
More in general, what is the best way to achieve this in SQL?
If, as I'm guessing from the column name, PublicationDate doesn't change, you can do this in two separate queries:
Establish the PublicationDate of the Article with Id == 100
Retrieve the 20 articles from that date onwards
Something like:
var thresholdDate = db.Articles.Single(a => a.Id == 100).PublicationDate;
var articles =
db.Articles
.Where(a => a.PublicationDate <= thresholdDate)
.OrderByDescending(a => a.PublicationDate)
.Take(20);
It might even be that LINQ to SQL can translate this:
var articles =
db.Articles
.Where(a => a.PublicationDate
<= db.Articles.Single(aa => aa.Id == 100).PublicationDate)
.OrderByDescending(a => a.PublicationDate)
.Take(20);
but that may be too complex for it. Try it and see.
You can try like this
var articles =
db.Articles
.Where(a => a.PublicationDate < db.Articles
.Where(aa => aa.Id==100)
.Select(aa => aa.PublicationDate)
.SingleOrDefault())
.OrderByDescending(a => a.PublicationDate)
.Take(20);
Isnt the solution to just add a where statement?
IQueryable<Article> articles = db.Articles.Where(a => a.id != 100).OrderByDescending(a => a.PublicationDate).Take(20);