When is OrderBy operator called? - linq

1)
a)
var result1 = from artist in artists
from album in artist.Albums
orderby album.Title,artist.Name
select new { Artist_id = artist.id, Album_id = album.id };
Is the above query translated into:
var result = artists.SelectMany(p => p.albums
.Select(p1 => new { Artist = p, Album = p1 }))
.OrderBy(p2 => p2.Album.Title)
.ThenBy(p3 => p3.Artist.Name)
.Select(p4 => new { Artist_id = p4.Artist.id, Album_id = p4.Album.id });
b)
I'm not sure if this question will make much sense - If my assumptions are correct and thus OrderBy is always one of the last operators to get called ( when using query expression ), then how would we express the following code using query expression (in other words, how do we specify in a query expression that we want OrderBy operator to get called sooner and not as one of the last operators ):
var result = artists
.SelectMany(p1 => p1.albums
.OrderBy(p2=>p2.title)
.Select(p3 => new { ID = p3.id, Title = p3.title }));
2) Do in the following query expression the two orderby clauses get translated into OrderBy(... artist.Name).OrderBy( ... album.Title):
var result1 = from artist in artists
from album in artist.Albums
orderby artist.Name
orderby album.Title
select new { ...};
thank you

For question 1: orderby gets called wherever you show it. Your query isn't quite equivalent to what you showed, but it's close. It doesn't help that you formatted it so that it looks like the Select is called on the result of SelectMany, when it's actually on the arguments to SelectMany. Your query is translated to something more like:
var result = artists
.SelectMany(artist => artist.albums, (artist, album) => new {artist, album})
.OrderBy(z => z.album.Title)
.ThenBy(z => z.artist.Name)
.Select(z => new { Artist_id = z.artist.id, Album_id = z.album.id }
Question 1b) Your query is roughly equivalent to:
var result = from p1 in artists
from p3 in (from p2 in p1.albums
orderby p2.title
new { ID = p2.id, Title = p2.title })
select p3;
It's only a rough translation as nothing in query expressions is converted to that overload of SelectMany, as far as I can remember. On the other hand, it could be that this does what you want in a slightly simpler way:
var result = from p1 in artists
from p3 in p1.albums.OrderBy(p2 => p2.title)
select new { ID = p3.id, Title = p3.title };
You'll still get the ordering within the artist. It's a mixture of query expression and "dot notation", but it looks good to me. Odd that you're not using p1 in the final result, mind you...
For question 2, using two orderby clauses you do indeed get two OrderBy calls, which is almost certainly not what you want. You want:
var result1 = from artist in artists
from album in artist.Albums
orderby artist.Name, album.Title
select new { ...};
That gets translated into the appropriate OrderBy(...).ThenBy(...) calls.

Related

Filter list having two Tables join data in Entity Framework

I have two tables..
Student (StudentId,Name,FatherName)
Qualification (QualificationId,StudentId,DegreeName)
I have got data like this..
var myList = (from c in entities.Students
join q in entities.Qualifications on c.StudentId equals q.StudentId
select new {c.Name,c.FatherName,q.DegreeName}).ToList();
Now i want to filter myList more.. How can i do it, like..
var filteredList = myList.Select(c=> new Student
{
Name=c.Name,
FatherName=c.FatherName
//Degree=C.Degree
}).ToList();
The above Linq Query is not working if i want to get DegreeName also, My Question is how to further Filter myList.
Thanks.
var filteredList = myList.Where(i => i.FatherName == "Shahid").ToList();
Keep in mind since you called ToList() on the original query you are now filtering in memory. If you want to filter in the database then remove the ToList() on the first query and do it like this:
var myList = from c in entities.Students
join q in entities.Qualifications on c.StudentId equals q.StudentId
select new {
c.Name,
c.FatherName,
q.DegreeName
};
var filteredInDatabase = myList.Where(i => i.FatherName == "Shahid").ToList();

how to use a dynamic variable in orderby clause

am a newbie in linq.. am stuck with one scenario. ie,
i have to sort the search results based on user input.
user inputs are Last Name, First Name and Title. for input 3 drop downs are there and i have to sort result based on the values selected.
i tried
order = Request["orders"].Split(',');
var param = order[0];
var p1 = typeof(Test).GetProperty(param);
param = order[1];
var p2 = typeof(Test).GetProperty(param);
param = order[2];
var p3 = typeof(Test).GetProperty(param);
model.Test = (from tests in model.Test
select tests).
OrderBy(x => p1.GetValue(x, null)).
ThenBy(x => p2.GetValue(x, null)).
ThenBy(x => p3.GetValue(x, null));
but it doesn't works.
i want qry like this
from tests in model.Test
select tests).OrderBy(x => x.lastname).
ThenBy(x => x.firstname).ThenBy(x => x.Title);
order[0]== lastname but how can i use it in the place of OrderBy(x => x.order[0])..?
Thanks in advance.
i solved my case as follows
// list of columns to be used for sorting
List<string>order = Request["orders"].Split(',').ToList();
//map the column string to property
var mapp = new Dictionary<string, Func<Test, string>>
{
{"FirstName", x => x.FirstName},
{"LastName", x => x.LastName},
{"SimpleTitle", x => x.SimpleTitle}
};
//user inputted order
var paras = new List<Func<Test, string>>();
foreach (var para in order)
{
if(!string.IsNullOrEmpty(para))
paras.Add(mapp[para]);
}
//sorting
model.Test= model.Test.OrderBy(paras[0]).ThenBy(paras[1]).ThenBy(paras[2]);
Thanks all,
Actually you are looking for dynamic linq query than you can try out Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
which allow to do like this
it means you can dynamically pass string propertyname to short you collection in orderby function
You can also read about : Dynamic query with Linq
You can compose the expression (any Expression) manually from pieces and then append it to the previous part of query. You can find more info, with example in "Sorting in IQueryable using string as column name".

Linq expression for left join and filter for the inner table

I want to know how to make Linq expression that has the same effect as these SQL query
SELECT item.*, priceforitem.*
FROM
item
LEFT JOIN priceforitem
ON priceforitem.ItemID = item.ItemID
AND priceforitem.PriceID = ?PriceID
I already make it using the Method query but I don't know if it will produce the same result
db.Items
.GroupJoin(
db.PriceForItems.Where(pi => pi.PriceID == id),
i => i.ItemID,
pi => pi.ItemID,
(i, pi) => new { Item = b, Prices = pi })
.SelectMany(
a => a.Prices.DefaultIfEmpty(),
(i, pi) => new
{
ItemID = i.Item.ItemID,
Code = i.Item.Code,
Name = i.Item.Name,
PriceForItemID = pi.PriceForItemID,
Price = pi.Price
})
and then after thinking for awhile i shorten it like this
db.Items
.SelectMany(
i => db.PriceForItems.Where(
pi => pi.PriceID == id
&& pi.ItemID = i.ItemID).DefaultIfEmpty(),
(i, pi) => new
{
ItemID = i.Item.ItemID,
Code = i.Item.Code,
Name = i.Item.Name,
PriceForItemID = pi.PriceForItemID,
Price = pi.Price
})
I am new to Linq, and I don't know which is better and how to convert it to Linq query statement.
First of all your sql query. It is effectively and inner join because the where condition will filter out all rows where data from priceforitem is null. If you do want to convert same query to linq you can do it like
from i in db.Items
join p in db.PriceforItems on
i.ItemId equals p.ItemId into tempvals
from t in tempvals.DefaultIfEmpty()
where t.PriceId == id
select new{i.ItemId, ..., t.PriceId, t...., t....}
I mostly write linq queries instead of expressions where they are more readable to me. If you still want to get an expression, you can write a valid linq query and paste it into Linqpad and it will give the result as well as lambda expression of your query.

Entity Framework 4 - What is the syntax for joining 2 tables then paging them?

I have the following linq-to-entities query with 2 joined tables that I would like to add pagination to:
IQueryable<ProductInventory> data = from inventory in objContext.ProductInventory
join variant in objContext.Variants
on inventory.VariantId equals variant.id
where inventory.ProductId == productId
where inventory.StoreId == storeId
orderby variant.SortOrder
select inventory;
I realize I need to use the .Join() extension method and then call .OrderBy().Skip().Take() to do this, I am just gettting tripped up on the syntax of Join() and can't seem to find any examples (either online or in books).
NOTE: The reason I am joining the tables is to do the sorting. If there is a better way to sort based on a value in a related table than join, please include it in your answer.
2 Possible Solutions
I guess this one is just a matter of readability, but both of these will work and are semantically identical.
1
IQueryable<ProductInventory> data = objContext.ProductInventory
.Where(y => y.ProductId == productId)
.Where(y => y.StoreId == storeId)
.Join(objContext.Variants,
pi => pi.VariantId,
v => v.id,
(pi, v) => new { Inventory = pi, Variant = v })
.OrderBy(y => y.Variant.SortOrder)
.Skip(skip)
.Take(take)
.Select(x => x.Inventory);
2
var query = from inventory in objContext.ProductInventory
where inventory.ProductId == productId
where inventory.StoreId == storeId
join variant in objContext.Variants
on inventory.VariantId equals variant.id
orderby variant.SortOrder
select inventory;
var paged = query.Skip(skip).Take(take);
Kudos to Khumesh and Pravin for helping with this. Thanks to the rest for contributing.
Define the join in your mapping, and then use it. You really don't get anything by using the Join method - instead, use the Include method. It's much nicer.
var data = objContext.ProductInventory.Include("Variant")
.Where(i => i.ProductId == productId && i.StoreId == storeId)
.OrderBy(j => j.Variant.SortOrder)
.Skip(x)
.Take(y);
Add following line to your query
var pagedQuery = data.Skip(PageIndex * PageSize).Take(PageSize);
The data variable is IQueryable, so you can put add skip & take method on it. And if you have relationship between Product & Variant, you donot really require to have join explicitly, you can refer the variant something like this
IQueryable<ProductInventory> data =
from inventory in objContext.ProductInventory
where inventory.ProductId == productId && inventory.StoreId == storeId
orderby inventory.variant.SortOrder
select new()
{
property1 = inventory.Variant.VariantId,
//rest of the properties go here
}
pagedQuery = data.Skip(PageIndex * PageSize).Take(PageSize);
My answer here based on the answer that is marked as true
but here I add a new best practice of the code above
var data= (from c in db.Categorie.AsQueryable().Join(db.CategoryMap,
cat=> cat.CategoryId, catmap => catmap.ChildCategoryId,
cat, catmap) => new { Category = cat, CategoryMap = catmap })
select (c => c.Category)
this is the best practice to use the Linq to entity because when you add AsQueryable() to your code; system will converts a generic System.Collections.Generic.IEnumerable to a generic System.Linq.IQueryable which is better for .Net engine to build this query at run time
thank you Mr. Khumesh Kumawat
You would simply use your Skip(itemsInPage * pageNo).Take(itemsInPage) to do paging.

How to access grouped values returned by a linq query

I've got the following code:
List<Person> people = new List<Person>
{
new Person{ Id = 1, Name = "Bob"},
new Person{ Id = 2, Name = "Joe"},
new Person{ Id = 3, Name = "Bob"}
};
var peopleGroupedByName = from p in people
group p by p.Name;
//get all groups where the number of people in the group is > 1
For the life of me I can't figure out how to work with the values returned by the linq query to be able to then filter all of the groups that were returned so that I only have the groups that have more than one item in them.
At the moment I'm banging my head against a wall and I can't quite think of what keywords to use in a google search in order to figure it out for myself.
I'd really appreciate any help on how to do this in Linq cause it seems like it should be very simple to do.
List<Person> people = new List<Person> {
new Person{ Id = 1, Name = "Bob"},
new Person{ Id = 2, Name = "Joe"},
new Person{ Id = 3, Name = "Bob"}
};
var peopleGroupedByName = from p in people
group p by p.Name into peopleGroup
where peopleGroup.Count() > 1
select peopleGroup;
//get all groups where the number of people in the group is > 1
Alternatively, where peopleGroup.Skip(1).Any() as Mehrdad has suggested will generally provide better performance with Linq to Objects since Count() iterates over the entire group's contents, and Skip(1).Any() merely over the first 2 elements - (see his comment for details; Count is fine for group-by clauses).
Aside: For readability, I prefer consistently using either the .GroupBy(... extension method syntax or the group ... by ... into ... query syntax but not both.
var peopleGroupedByName = people.GroupBy(p => p.Name)
.Where(g => g.Count() > 1);
var peopleGroupedByName = from p in people
group p by p.Name into g
where g.Count() > 1
select g;
This is actually quite easy.
var filtererGroups = people
.GroupBy(p => p.Name)
.Where(grp => grp.Count() > 1);
To filter by key you would do something like that.
var filtererGroups = people
.GroupBy(p => p.Name)
.Where(grp => grp.Key == "Bob");

Resources