I have been working on a linq query for some hours but not getting it to work.
I'm trying to compare some list of data to another list of data and I don't see why it's not working as expected.
I have a DbSet and Room has a list of Facilities and every Facility has it's own Id.
So my method takes a list of facilityId's (IEnumerable) and I want to return all rooms that matches the list of facilities.
So I thought my query could look like this:
var rooms = DbSet.Include("Facility").Where(room => room.Facility.All(facility => facilityIds.Contains(facility.Id)));
But this query is giving me other results than expected. Anyone can give me hand with fixing this query?
Update sample
var filterIds = new int[] {1,2};
var facilities1 = new List<Facility> {new Facility() {Id = 1}};
var facilities2 = new List<Facility> {};
var facilities3 = new List<Facility> {new Facility() {Id = 1}, new Facility() {Id = 2}};
var basicData = new List<Room>()
{
new Room() {Id = 1, Facility = facilities1},
new Room() {Id = 2, Facility = facilities2},
new Room() {Id = 3, Facility = facilities1},
new Room() {Id = 4, Facility = facilities3},
new Room() {Id = 5, Facility = facilities1},
new Room() {Id = 6, Facility = facilities1},
};
var result = basicData.Where(r => (!filterIds.Any() || r.Facility.All(f => filterIds.Contains(f.Id))));
This query is giving me 6 results and I'm expecting only the room with Id 4.
Would this work?
rooms.Where(
room => room.Facilities.Any()
&& filterIds.All(x => room.Facilities.Any(o => o.Id == x))
);
Update
Updated fiddle with your sample data. Returns room 4 as expected for facilities 1,2. Returns rooms 1,3,4,5,6 for just facility 1:
Fiddle: https://dotnetfiddle.net/b24FbF
Related
I have a list of objects like:
var list = new List<someUi>
{
{Name="Arjun", Salary=100, Div="A"},
{Name="Dani", Salary=50, Div="B"},
{Name="Nick", Salary=75, Div="C"},
{Name="Arjun", Salary=55, Div="A"},
{Name="Dani", Salary=10, Div="B"}
}
Now I want to merge the list based one Name (GroupBy Name) and want to total the Salary.
so, My expected output is like this:
var list = new List<someUi>
{
{Name="Arjun", Salary=155, Div="A"},
{Name="Dani", Salary=60, Div="B"},
{Name="Nick", Salary=75, Div="C"}
}
How can I do that using C# or LINQ.
Thanks in advance.
try this:
var list = new List<someUi>()
{
new someUi() {Name = "Arjun", Salary = 100, Div = "A"},
new someUi() {Name = "Dani", Salary = 50, Div = "B"},
new someUi() {Name = "Nick", Salary = 75, Div = "C"},
new someUi() {Name = "Arjun", Salary = 55, Div = "A"},
new someUi() {Name = "Dani", Salary = 10, Div = "B"}
};
var grouped = list.GroupBy(x => x.Name).Select(x=> new someUi { Name=x.Key,Salary = x.Sum(x=>x.Salary),Div = x.First().Div}).ToList();
Based on your expected result you may need to group by the list based on both Div and Name, So try this one:
var result = list.GroupBy(g => new {g.Name, g.Div})
.Select(s => new someUi {
Name = s.Key.Name,
Div = s.Key.Div,
Salary = s.Sum(t => t.Salary)
}).ToList();
How can I re-write the following query from SQL to lambda in C#? Is it recommended to write in lambda?
SELECT *
FROM Claims
WHERE id IN (SELECT claimId
FROM MissingItems
GROUP BY claimId);
Equivalent using LINQ lambdas - assuming you have a collection of MissingItem objects in your code (and a representation of Claim in your code)
List<String> distinctClaimIds = missingItems.Select(mi => mi.claimId).Distinct();
List<Claim> claimsWithThoseIds = claims.Where(c => distinctClaimIds.Contains(c.id)).ToList();
Edit for your "one statement" interest:
Closest to "one statement" (even though I think 2 is more readable) I can think of:
List<Claim> claimsWithThoseIds = claims.Where(c => missingItems.Select(mi => mi.claimId).Distinct().Contains(c.id)).ToList()
You can use Join to do this in one "line":
class MissingItems
{
public string Id {get;set;}
}
class Claims
{
public string ClaimId {get;set;}
}
void Main()
{
List<MissingItems> mi = new List<MissingItems>() {
new MissingItems() {Id = "a"},
new MissingItems() {Id = "b"},
new MissingItems() {Id = "c"},
new MissingItems() {Id = "d"},
};
List<Claims> cl = new List<Claims>() {
new Claims() {ClaimId = "a"},
new Claims() {ClaimId = "f"},
new Claims() {ClaimId = "c"},
new Claims() {ClaimId = "d"},
};
var a = mi.Join(cl, m => m.Id, c => c.ClaimId, (m,c) => {
return new { Claim = c.ClaimId, Missing = m.Id};
});
foreach(var b in a)
{
Console.WriteLine("Claim: " + b.Claim + " Missing: " + b.Missing);
}
}
This will join the ClaimId from Claims on the MissingItems Id property. The output looks like this:
Claim: a Missing: a
Claim: c Missing: c
Claim: d Missing: d
I am currently developing an application that requires this senario.
Assuming I have this object
public class ObjectItem
{
public int Id {get;set;}
public int Name {get;set;}
public int Sex {get;set;}
public int Age {get;set;}
public string Complexion {get;set;}
}
If we now have two lists of this object
var studentWithAge = new List<ObjectItem>
{
new ObjectItem {Id = 1, Name = "John", Age = 2},
new ObjectItem {Id = 2, Name = "Smith", Age = 5},
new ObjectItem {Id = 3, Name = "Juliet", Age = 7},
};
var studentWithSexAndComplexion = new List<ObjectItem>
{
new ObjectItem {Id = 1, Name = "John", Sex = "Male", Complexion = "fair"},
new ObjectItem {Id = 2, Name = "Smith", Sex = "Male", Complexion = " "},
new ObjectItem {Id = 3, Name = "Juliet", Sex = "Female", Complexion = "Blonde"},
new ObjectItem {Id = 4, Name = "Shittu", Sex = "Male", Complexion = "fair"},
};
I want to merge these two lists into just one. The end result should look like this.
var CompleteStudentData=new List<ObjectItem>
{
new ObjectItem{Id=1,Name="John",Sex="Male", Complexion="fair",Age=2},
new ObjectItem{Id=2,Name="Smith",Sex="Male", Complexion=" ", Age=5},
new ObjectItem{Id=3,Name="Juliet",Sex="Female", Complexion="Blonde", Age=7},
new ObjectItem{Id=4,Name="Shittu",Sex="Male", Complexion="fair", Age=0},
}
How do i achieve this? Using Union to merge the two list does not produce the desired result. I would appreciate your help.
var result = StudentWithAge.Join(StudentWithSexAndComplexion,
sa => sa.Id,
ssc => ssc.Id,
(sa, ssc) => new ObjectItem
{
Id = sa.Id,
Name = sa.Name,
Age = sa.Age,
Sex = ssc.Sex,
Complexion = ssc.Complexion
}).ToList();
Or, avoiding creation of new objects:
var result = StudentWithAge.Join(StudentWithSexAndComplexion,
sa => sa.Id,
ssc => ssc.Id,
(sa, ssc) =>
{
sa.Sex = ssc.Sex;
sa.Complexion = ssc.Complexion;
return sa;
}).ToList();
And if you want to add students presented only in the second list, than also:
result.AddRange(StudentWithSexAndComplexion.Where(ssc => !StudentWithAge.Any(sa => sa.Id == ssc.Id)));
Since it's possible that your collections will not have a 1-to-1 correspondence, you would have to do a full outer join. See here for how you can compose it that way.
Here's one way you can get similar results.
Collect all the keys (the ids) from both collections, then perform a left join with each of the collections, then combine the results.
var ids = studentWithAge.Select(s => s.Id)
.Union(studentWithSexAndComplexion.Select(s => s.Id));
var query =
from id in ids
from sa in studentWithAge
.Where(sa => sa.Id == id)
.DefaultIfEmpty(new ObjectItem { Id = id })
from ssc in studentWithSexAndComplexion
.Where(ssc => ssc.Id == id)
.DefaultIfEmpty(new ObjectItem { Id = id })
select new ObjectItem
{
Id = id,
Name = sa.Name ?? ssc.Name,
Sex = ssc.Sex,
Age = sa.Age,
Complexion = ssc.Complexion,
};
.Net has a function which is concatenating collections:
var concatenatedCollection = StudentWithAge.Concat(StudentWithSexAndComplexion).ToList();
var StudentWithAge = new List<ObjectItem>()
{
new ObjectItem{Id=1,Name="John",Age=2},
new ObjectItem{Id=2,Name="Smith",Age=5},
new ObjectItem{Id=3,Name="Juliet",Age=7},
};
var StudentWithSexAndComplexion = new List<ObjectItem>()
{
new ObjectItem{Id=1,Name="John",Sex="Male", Complexion="fair"},
new ObjectItem{Id=2,Name="Smith",Sex="Male", Complexion=" "},
new ObjectItem{Id=3,Name="Juliet",Sex="Female", Complexion="Blonde"},
new ObjectItem{Id=4,Name="Shittu",Sex="Male", Complexion="fair"},
};
var concatenatedCollection = StudentWithAge.Concat(StudentWithSexAndComplexion).ToList();
I'm new to linq and I have 3 tables with these columns.
Trainee (ID, TraineeName)
Course (ID, CourseName)
TraineeCourseEnrollment (TraineeID, CourseID, EnrolledDate)
I created a stored procedure to get un-enrolled courses using this query.
select *
from Course
where ID not in (select CourseID
from TraineeCourseEnrollment
where TraineeID = #traineeid);
How to write the corresponding linq query to this SQL query using extension methods?
You will have to do two queries, first to retrieve the IDs that you want to exclude and the second to get actual courses:
var excludeIDs = db.TraineeCourseEnrollments.Where(w => w.TraineeID == traineeid).Select(s => s.CourseID);
var courses = db.Courses.Where(w =>!excludeIDs.Contains(w.ID)).ToList();
Something like this:
Extensions methods:
int traineeid = ...;
var query = dc.Courses
.Where(c => ! dc.TraineeCourseEnrollments
.Where(o => o.TrainessID == traineeid)
.Select(o => o.CourseID)
.Contains(c.ID));
LINQ query:
int traineeid = ...;
var query =
from c in dc.Courses
where !(from o in dc.TraineeCourseEnrollments
where o.TraineeID == traineeid
select o.CourseID)
.Contains(c.ID)
select c;
var prospectus = new []
{
new { CourseId = "C1", CourseName = "Database" },
new { CourseId = "C2", CourseName = "HCI" },
new { CourseId = "C3", CourseName = "Op Systems" },
new { CourseId = "C4", CourseName = "Programming" }
};
var enrollment = new []
{
new { TraineeID = "T1", CourseId = "C1", Date = new DateTime(2014, 12, 01) },
new { TraineeID = "T2", CourseId = "C1", Date = new DateTime(2014, 12, 05) },
new { TraineeID = "T1", CourseId = "C3", Date = new DateTime(2014, 12, 01) }
};
var notMatchingQueryStyle = from c in prospectus
where !enrollment.Any(r => c.CourseId == r.CourseId)
select c;
Resharper nags me to "simplify" this using All instead of Any, go figure:
var notMatchingQueryStyle = from c in prospectus
where enrollment.All(r => c.CourseId != r.CourseId)
select c;
I'm trying to convert this LINQ method expression to an equivalent query syntax:
var results1 =
logins.GroupBy(loginDate => loginDate.Date)
.Select(loginDates => new
{
Date = loginDates.Key,
Count = loginDates.Select(login => login.Name).Distinct().Count()
});
First, I came to this syntax, which does provide the same result, but isn't really the same.
var results2 =
from loginDate in logins
group loginDate by loginDate.Date
into loginDates
select new
{
Date = loginDates.Key,
Count = (from login in loginDates group login by login.Name).Count()
};
The difference is that I'm using a group by statement here, which isn't the same as distinct (although it does provide the same result). Then I tried this:
var results3 =
from loginDate in logins
group loginDate by loginDate.Date
into loginDates
select new
{
Date = loginDates.Key,
Count = (from login in loginDates select login.Name).Distinct().Count()
};
However, this code is using quite some method syntax again.
It my last example the best you can get? Or is it possible to rewrite the query using less method syntax and more query syntax?
The logins is initialized like this:
var logins = new[]
{
new {Name = "james", Date = new DateTime(2011, 01, 01)},
new {Name = "jamie", Date = new DateTime(2011, 01, 01)},
new {Name = "alex", Date = new DateTime(2011, 01, 01)},
new {Name = "james", Date = new DateTime(2011, 1, 1)},
new {Name = "matt", Date = new DateTime(2011, 1, 2)},
new {Name = "jamie", Date = new DateTime(2011, 1, 2)},
new {Name = "alex", Date = new DateTime(2011, 1, 2)},
new {Name = "james", Date = new DateTime(2011, 1, 2)},
new {Name = "james", Date = new DateTime(2011, 1, 2)}
};
There isn't a query form for Distinct (see this post for why). The query syntax with group by is semantically equivalent, and is what I would go with if you want it in query form.
afaik, LINQ query syntax has no Distinct() equivalent. Neither Count(), Sum(), etc. So you have to combine method/query syntax or use just method.