Can this code be converted into a single linq statement? - linq

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));

Related

Shortcut LINQ toentity query for the following code in MVC 3

I have entities which are indeirectly connected. Here, Task is connected to Sprint indirectly. One BacklogItem can have several Task and each BacklogItem belongs to one Sprint. So, In my application I needed all the Tasks belonging to some sprint. Since they do not connect directly, I had to write a many code lines which is below:
public viewResult tasksForSprint(int sprintId){
List<Task> tasksforSprint = new List<Task>();
var backlogItemlsit = db.BacklogItems.Where(b => b.sprintId == sprintId).OrderBy(i => i.backlogId).ToList();
var sprintTaskItems = db.Tasks.OrderBy(i => i.taskId).ToList();
foreach (var item in sprintTaskItems)
{
if (backlogItemlsit.Any(b => b.backlogId == item.backlogId))
taskforSprint.Add(item);
}
return view(tasksforSprint);
}
Now, what I want is get that List tasksforSprint with one LINQ query rather than 6 lines of code.
Thanks in advance.
Looks like it's a join. Untested:
db.BacklogItems
.Where(b => b.sprintId == sprintId)
.Join(db.Tasks,
// outer join key
sprint => sprint.backlogId,
// inner join key
task => task.backlogId,
// result selector -- take the tasks
(outer, inner) => inner)
.OrderBy(task => task.taskId)
.ToList();

linq filtering child collection

I have read over a bunch of different topics on this, but i havent found what I am looking for.
I have an EF query that is this:
var query = this.ObjectContext.Questions
.Include("AnswerKey").Include("QuestionTypes")
.Where(o => o.SurveyQuestions.Any(o2 => o2.SurveyID == id));
This was working fine until i realized that i was not taking into account my Active Flag for the AnswerKey child collection. In other words, this query should load all questions that have a parent surveyid of 3(which it does)but only load AnswerKeys that have an active flag of true.
I have tried this:
var query = this.ObjectContext.AnswerKey
.Include("Questions.QuestionTypes")
.Where(ak =>
ak.Active == true &&
ak.Questions.SurveyQuestions.Any(sq => sq.SurveyID == 3) &&
ak.Questions.Active == true)
.AsEnumerable()
.Select(ak => ak.Questions).AsQueryable();
But it returns 1 question for each answerkey. So if a question has 4 answer it shows up 4 times...
How can i do this?
You could just use Distinct() at the end to filter out the duplicates:
.AsEnumerable()
.Select(ak => ak.Questions)
.Distinct()
.AsQueryable();
Brokenglass I will try your suggestion. And give you the credit if it works..
I also found this here after following another link on SO... and this appears to work as well but i need to verify it in my app.

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.

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

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

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Resources