LINQ ordering with multiple joins - c#

Basic schema that I have inherited (no foreign keys):
Tasks (TaskID, Description, ElementID, UserID)
Elements (ElementID, Description)
Users (UserID, FirstName, LastName)
I need to order a List<Task>, first by Element.Description, then by User.FirstName, then by User.LastName
I've managed so far to order by Element.Description using the following:
List<Task> tasks = db.Tasks.ToList();
List<Element> elements = db.Elements.ToList();
List<User> users = db.Users.ToList();
tasks = tasks.Join(elements,
t => t.ElementID,
e => e.ElementID,
(t, e) => new { t, e })
.OrderBy(m => m.e.Description)
.Select(m => m.t).ToList();
How do I join/order with more than one other entity? (ie. I need to add users to the above query and order by its fields)
(I know query syntax might be more suitable for joins but I've become more familiar/comfortable with lambda syntax, so it would be preferred)

You first need to Join the result of your first Join with the list of User, then use ThenBy to order by the User fields :
tasks = tasks
.Join(elements,
t => t.ElementID,
e => e.ElementID,
(t, e) => new { t, e })
.Join(users,
x => x.t.UserID,
u => u.UserID,
(x, u) => new { x.t, x.e, u })
.OrderBy(m => m.e.Description)
.ThenBy(m => m.u.FirstName)
.ThenBy(m => m.u.LastName)
.Select(m => m.t)
.ToList();

Related

OrderBy items inside GroupJoin queryable by string list

results = await query
.GroupJoin(_invitations.GetAll().AsNoTracking()
.Where(i => i.GroupId == groupId),
user => user.Id,
invitation => invitation.UserId,
(a, s) => new { User = a, Invitation = s})
.SelectMany(
ai => ai.Invitation.DefaultIfEmpty(),
(a, s) => new { Users = a.User, Invitations = s }
)
.Select(i => i.Users)
.Skip(skip)
.Take(take)
.ToListAsync();
Howdy. I have quite simple group join but I can't figure out how to sort invitations inside this group join. Problem is, I don't want to make simple orderBy(i => i.creationDate) but I want to do something like (but on queryable):
var list = new List<string> {"Fall","Mid","Spring"};
return _db.MiaLog1A.Where(m => m.Campus == selectedCampus)
.AsEnumerable()
.OrderBy(m => m.StudentName)
.ThenBy(m=> list.IndexOf(m.Term));
I need to order them by specific strings. Because I have a scenario where newest invitation isn't what I need. I want accepted invitation status first. Is there a way to do this?
I've tried things like that:
.OrderBy(i => sortOrderList.IndexOf(i.InvitationsStatus) in many places but it just throws.
Thank you in advance.
A pattern of
.OrderBy(m => m.StudentName)
.ThenBy(m => m.X == "y" ? 0 : (m.X == "x" ? 1:2))
Should translate if you want to sort by "y","x","z"
But I note that both examples you given; (fall, mid, spring) and (approved vs pending / not invited) are sorted in that order anyway.. you don't need to sort by the list index of these, you can just sort the strings ascending

LINQ lambda expression query to join more number of table with different where condition

First I have to filter the value based on the Condition value in Table1.
Then I have to join another table called Table2 from Table1. Those two tables have common field Condition2.
At last I should get the value based on the Final condition by joining the Table2 and Table3 common condition (Final_Condition) satisfied values.
I have used below query to get the data. But I got the cross joined result.
var result = db.Table1
.Where(m => m.u.Condition == "Condition")
.Join(db.Table2, u => u.Number, uir => uir.Number, (u, uir) => new { u, uir })
.Where(m => m.u.Condition2 == m.uir.Condition2)
.Join(db.Table3, proposal => proposal.uir.ID.Leasing_Proposal_Id, prop => prop.ID,
(proposal, prop) => new
{
proposal.u,
proposal.uir,
prop
})
.Where(m => m.uir.FinalCondition == m.prop.FinalCondition)
.AsEnumerable()
.Select(m => new Model
{
Name = m.Name,
Id = m.Id,
Dept = m.Dept
})
.Where(m => ((m.Name != null) ? m.Name.ToUpper().Contains("xxx") : false))
.Cast<IResult>()
.ToList();

Compare Matching Element using single query in Iqueryable

I am trying to compare two List of UserGroup from two different Table using a single query ie, by not hitting DB multiple times.
currently I am fetching all assigned UserGroup in one query, and comparing with all allowed Usergroup in other query.
var query = _context.AppSubOperationUserGroupMappings.Where(filterPredicate)
.Select(x => x.UserGroup)
.ToList();
var allowedUserGroups = _context.Users.Where(x => x.Id == userId)
.Select(x => x.UserGroupUserMappings.Select(y => y.UserGroup))
.First()
.ToList();
return query.Any(a => allowedUserGroups.Any(b => b.Id == a.Id));
How can I merge them into single Query?
Remove ToList and First, use Join and SelectMany
var query = _context.AppSubOperationUserGroupMappings.Where(filterPredicate)
.Select(x => x.UserGroup);
var allowedUserGroups = _context.Users.Where(x => x.Id == userId)
.SelectMany(x => x.UserGroupUserMappings, (x, y) => y.UserGroup);
return query
.Join(
allowedUserGroups,
x => x.Id,
x => x.Id,
(x, y) => false) // doesn't matter what to select
.Any();

How to create a linq lambda join query that pulls results even though there null results?

I have this join query that pulls all school programs and products that is in a person's shopping cart:
//this pulls all items the user purchased
var poop = Context.Query<Cart>().Where(x => x.UserId == currentUserId && x.Status == "Archived")
.Select(
p => new
{
p.ItemId,
p.TypeId,
p.PurchaseDate
})
//This get the media type name of the cart items
.Join(
Context.Query<MediaType>(),
t => new {t.TypeId},
m => new {TypeId = m.Id},
(t, m) => new
{
t.ItemId,
t.TypeId,
t.PurchaseDate,
m.TypeName
}).OrderBy(d => d.PurchaseDate)
//Now i need specifics of the items like name, sku, etc. StartDate will be null for items that are products, but contains DateTime for items that are programs.
.Join(
Context.Query<ProgramProductView>(),
e => new {e.ItemId, e.TypeId},
prog => new {ItemId = prog.Id, prog.TypeId},
(e, prog) => new
{
e.ItemId,
e.TypeId,
e.PurchaseDate,
e.TypeName,
prog.FullName,
prog.StartDate,
prog.Sku,
prog.Closed
}).OrderBy(d => d.PurchaseDate);
So right there is where it crashes because prog.StartDate is null for products. I get SQL is not available error.
Is there a way to have the join allow null-able fields? I am only using lambda because it's easier to read and clean.
Well you just need to use Nullable<> property for you anonymous class in your last Join:
.Join(
Context.Query<ProgramProductView>(),
e => new {e.ItemId, e.TypeId},
prog => new {ItemId = prog.Id, prog.TypeId},
(e, prog) =>
new
{
...
(DateTime?)prog.StartDate,
...
}).OrderBy(d => d.PurchaseDate);
Hope it will help.

LinQ method syntax multiple tables with .where() and without joins

How do fetch data from multiple tables with method syntax without using joins, but only .where() methods?
I'm making a select against EF5 db context which maps to this legacy table structure where I have a persons detail table and another table which refers both to itself to create a hierarchy and to the person details table this way:
PersonSet
.Where(p => p.LastName.ToLower()=="surname")
.Join(SubsetSet, p => p.Id, ss => ss.SubsetLink, (p, ss) => new { PersonDetail = p, person = ss })
.Where(m => m.person.Frame=="a" && m.person.Purpose=="1")
.Join(SubsetSet, ss1 => ss1.person.Owner, person => person.SubsetLink, (ss1, ss2) => new { person = ss1, club = ss2 })
.Where(a => a.club.Frame=="b" && a.club.Purpose=="2")
.Join(SubsetSet, ss => ss.club.Owner, ss2 => ss2.SubsetLink, (ss, ss2) => new { club = ss, association = ss2 })
.Where(a => a.association.Frame=="b" && a.association.Purpose=="3")
.Join(SubsetSet, ss => ss.association.Owner, ss3 => ss3.SubsetLink, (ss, ss3) => new { association = ss, district = ss3})
.Where(d => d.district.Frame=="b" && d.district.Purpose=="4" && d.district.SubsetLink=="12345")
.Select(proj => new { proj.association.club.person, proj.association.club, proj.association, proj.district })
.OrderByDescending(a => a.association.club.person.phyperson.FirstName)
.Take(10).Dump();
The above query works at least in LinqPad but, it seems to me that If I could get rid of those joins the statement might look a bit nicer. Now I know, like in the Albahari example below, that this can be done with query syntax. But I couldn't find an example that would illustrate this situation with method syntax. The way I'm trying to approach this might of course be wrong and that's why I can't find suitable examples.
Here I found something similar, but couldn't make it work in LinQPad:
Is multiple .Where() statements in LINQ a performance issue?
Or this one, where the solution is again in query syntax:
Cross Join with Where clause
Or this example by Albahari: (http://www.linqpad.net/WhyLINQBeatsSQL.aspx)
from p in db.Purchases
where p.Customer.Address.State == "WA" || p.Customer == null
where p.PurchaseItems.Sum (pi => pi.SaleAmount) > 1000
select p
Consider this query:
var q = from order in orders
from orderline in order.Lines
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => order.Lines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);
For more information on SelectMany, see the MSDN documentation.
If you don't have associations defined:
var q = from order in orders
from orderline in orderLines
where orderline.OrderId == order.Id
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => orderLines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.OrderId == item.order.Id)
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);

Categories