How do I merge two LINQ statements into one to perform a list2.Except(list1)? - linq

Currently, I have the following LINQ queries. How can I merge the two queries into one. Basically, write a LINQ query to bring back the results I'd get from
IEnumerable<int> deltaList = people2010.Except(allPeople);
except in a single query.
var people2010 = Contacts.Where(x => x.Contractors
.Any(d => d.ContractorsStatusTrackings
.Any(date => date.StatusDate.Year >= 2010)))
.Select(x => x.ContactID);
var allPeople = Contacts.Where(x => x.Contractors
.Any(m => m.ContactID == x.ContactID))
.Select(x=> x.ContactID);
Thanks!

Why can you not just do Except as you are doing? Don't forget that your people2010 and allPeople variables are just queries - they're not the data. Why not just use them as they are?
If that's not acceptable for some reason, please give us more information - such as whether this is in LINQ to Object, LINQ to SQL etc, and what's wrong with just using Except.

It sounds like you're just looking for a more elegant way to write your query. I believe that this is a more elegant way to write your combined queries:
var deltaList =
from contact in Contacts
let contractors = contact.Contractors
where contractors.Any(ctor => ctor.ContractorStatusTrackings
.Any(date => date.StatusDate.Year >= 2010))
&& !contractors.Any(m => m.ContactID == contact.ContactID)
select contact.ContactID

Related

Can this code be converted into a single linq statement?

I'm trying to filter a list within a list from an entity framework entity.
I've managed to get the code working however, i'm not convinced it's the cleanest way of achieving the goal.
Here's the code I have so far:
foreach (var n1 in tier.MatchNodes)
{
n1.LenderMatchNodes = n1.LenderMatchNodes.Where(x => x.Commission == 0).ToList();
}
Effectively MatchNodes contains a collection of LenderMatchNodes, however I want to return only the nodes where the commission == 0.
Thanks in advance.
Try
tier.MatchNodes.ToList().ForEach(n1=>n1.LenderMatchNodes = n1.LenderMatchNodes.Where(x => x.Commission == 0).ToList());
Try using SelectMany():
var result = dataContext.Table<Tier>()
.Where(some condition to get you the tier)
.SelectMany(tier => tier.MatchNodes)
.SelectMany(node => node.LenderMatchNodes)
.Where(x => x.Commission == 0)
.ToList();
This has the additional benefit of being able to execute it a single SQL query.
If you're goal is to actually update the node list in the database, you can still minimize the number of queries using Include() (assuming you're using EF):
var nodes = dataContext.Table<Tier>()
.Where(some condition to get you the tier)
.SelectMany(tier => tier.MatchNodes)
.Include(node => node.LenderMatchNodes) // loads this eagerly
.ToList();
nodes.ForEach(n => n.LenderMatchNodes = n.LenderMatchNodes.Where(condition));

Need some help on a somewhat complex LINQ query

I have this query that does what I want which is to return true if any of the materials is comparable in the material groups list.
mgroup.MaterialGroups.Select(x => x.Materials
.Any(m => Convert.ToBoolean(m.Comparable)))
.Any(x => x.Equals(true))
What I would like to add to this query is to also include this one.
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable));
How can I combine mgroup and it's materialgroups together in the query so I can select both of their Materials? Thanks.
EDIT - After fighting with LINQ for awhile I broke down and just combined as
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable) ||
mgroup.MaterialGroups.Select(x => x.Materials
.Any(c => Convert.ToBoolean(c.Comparable)))
.Any(x => x.Equals(true)))
It works as expected but it's horribly long and it's embedded in an Asp.net MVC view to makes things even worse. If anyone can simplify this that would be amazing.
P.S.- If you are wondering why I added the extra .Any(x => x.Equals(true) at the end it's because without it the query returns an IEnumerable of bools instead of bool.
IEnumerable<Material> allMaterials =
mgroup.Materials.Concat(
mgroup.MaterialGroups.SelectMany(group => group.Materials));
bool result = allMaterials.Any(m => Convert.ToBoolean(m.Comparable));

LINQ Order by question

I have a linq query that returns a list of employees and a job title.
I need to sort it by job title but have the ones that do not have any employees in the output list first.
Example sorted:
- Driver List{0}
- Attendant List{71}
- Pilot List{19}
The driver is first because it has nothing in the list and then it is sorted by title.
I am just curious what do you think would be my best option to accomplish that?
Thanks
Something like:
var query = employees.OrderBy(x => x.Subordinates.Any() ? 1 : 0)
.ThenBy(x => x.JobTitle);
You could also use the fact that false sorts earlier than true:
var query = employees.OrderBy(x => !x.Subordinates.Any())
.ThenBy(x => x.JobTitle);
... but that's a little bit less obvious, IMO.
Something like:
Jobs.OrderBy(j => j.Eployees.Count()).ThenBy(j => j.Name);

How to convert a LINQ query from query syntax to query method

Linq and EF4.
I have this Linq query in query syntax I would like convert into query method.
Are you able to do it? I tried more tha 2 hours without success :-(
Thanks for your time
CmsContent myContentObj = (from cnt in context.CmsContents
from categoy in cnt.CmsCategories
where categoy.CategoryId == myCurrentCategoryId && cnt.ContentId == myCurrentContentId
select cnt).Single();
My original answer selected the wrong item. It's a bit more complicated than what I had (which Ani has posted). Here's what I believe is an equivalent query however and should perform better:
CmsContent myContentObj =
context.CmsContents
.Where(cnt => cnt.ContentId == myCurrentId
&& cnt.CmsCategories
.Any(categoy => categoy.CategoryId == myCurrentCategoryId))
.Single();
Here is a non-direct translation that I believe performs the same task in much less code:
var myContentObj = context.CmsContents.Single(
x => x.ContentId == myCurrentContentId &&
x.CmsCategories.Any(y => y.CategoryId == myCurrentCategoryId)
);
Here's how the C# compiler actually does it, with some help from .NET Reflector to verify:
var myContentObj = context
.CmsContents
.SelectMany(cnt => cnt.CmsCategories,
(cnt, categoy) => new { cnt, categoy })
.Where(a => a.categoy.CategoryId == myCurrentCategoryId
&& a.cnt.ContentId == myCurrentContentId)
.Select(a => a.cnt)
.Single();
Essentially, the 'nested' from clauses results in a SelectMany call with a transparent identifier (an anonymous-type instance holding the 'parent' cnt and the 'child' categoy). The Where filter is applied on the anonymous-type instance, and then we do another Select projection to get back the 'parent'. The Single call was always 'outside' the query expression of course, so it should be obvious how that fits in.
For more information, I suggest reading Jon Skeet's article How query expressions work.

Lost with LINQ and Expressions

I'm trying to write a LINQ query on some objects where I need to only do a select if a filter value is set.
Is there a way to "change" the query dynamically to only do a select if this is set.
Use where to find the items of interest, e.g.:
collection.Where(i => PassesFilter(i)).Select(i => i.InterestingValue);
var query = Somthing().Where(x => x.IsSomethingYouAlwaysFilterBy);
if(FilterValueIsSet(filterValue))
{
query = query.Where(x => x.Property == filterValue)
}
I'm not sure I understand your question, but you can use predicate builder. Predicate Builder example here

Resources