Group by child table in LINQ - c#

I have students table and I have subjects tables I need to group students by subjects . I tried following which doesnt show s.StudentSubjects.SubjectName . How can I write group by with child table .
Students -> StudentID | Name
StudentSubjects -> SubjectID | StudentID | SubjectName
var list = from s in students
group s by s.StudentSubjects.? into g
select new StudentSubjectsCounts
{
Name = g.Key,
Count = g.Count(),
};

Sounds like you should query off of StudentSubjects instead of Student:
var list = from ss in studentSubjects
group ss by s.SubjectName into g
select new StudentSubjectsCounts
{
Name = g.Key,
Count = g.Count(),
};
Or, to start from a list of students:
var list = students.SelectMany(s => s.StudentSubjects)
.GroupBy(ss => ss.SubjectName)
.Select(g => new StudentSubjectsCounts
{
Name = g.Key,
Count = g.Count(),
});

You should be able to group by the StudentSubject object itself
var list = from s in students
group s by s.StudentSubjects into g
select new StudentSubjectsCounts
{
Name = g.Key.SubjectName,
Count = g.Count(),
};
but if you don't want to, project the name using a Select
var list = from s in students
group s by s.StudentSubjects.Select(ss => ss.SubjectName) into g
select new StudentSubjectsCounts
{
Name = g.Key,
Count = g.Count(),
};

Related

LINQ Query with GroupBy, MAX and Count

What could be the LINQ query for this SQL?
SELECT PartId, BSId,
COUNT(PartId), MAX(EffectiveDateUtc)
FROM PartCostConfig (NOLOCK)
GROUP BY PartId, BSId
HAVING COUNT(PartId) > 1
I am actually grouping by two columns and trying to retrieve max EffectiveDateUtc for each part.
This is what I could write. Stuck up on pulling the top record based on the date.
Also not sure, if this is a optimal one.
//Get all the parts which have more than ONE active record with the pat
//effective date and for the same BSId
var filters = (from p in configs
?.GroupBy(w => new
{
w.PartId,
w.BSId
})
?.Select(g => new
{
PartId = g.Key.PartId,
BSId = g.Key.BSId,
Count = g.Count()
})
?.Where(y => y.Count > 1)
select p)
?.Distinct()?.ToList();
var filteredData = (from p in configs
join f in filters on p.PartId equals f.PartId
select new Config
{
Id = p.Id,
PartId = p.PartId,
BSId = p.BSId,
//EffectiveDateUtc = MAX(??)
}).OrderByDescending(x => x.EffectiveDateUtc).GroupBy(g => new { g.PartId, g.BSId }).ToList();
NOTE: I need the top record (based on date) for each part. Was trying to see if I can avoid for loop.
The equivalent query would be:
var query =
from p in db.PartCostConfig
group p by new { p.PartId, p.BSId } into g
let count = g.Count()
where count > 1
select new
{
g.Key.PartId,
g.Key.BSId,
Count = count,
EffectiveDate = g.Max(x => x.EffectiveDateUtc),
};
If I understand well, you are trying to achieve something like this:
var query=configs.GroupBy(w => new{ w.PartId, w.BSId})
.Where(g=>g.Count()>1)
.Select(g=>new
{
g.Key.PartId,
g.Key.BSId,
Count = g.Count(),
EffectiveDate = g.Max(x => x.EffectiveDateUtc)
});

Group BY multiple using linq [duplicate]

This question already has answers here:
Group By Multiple Columns
(14 answers)
Closed 6 years ago.
Trying to group by multiple fileds but having issues with it. I want to group by period,productcode.
var ProductUsageSummary = from b in myProductUsage
group b by b.ProductCode into g
select new
{
Period = g.Key,
Code = g.Key,
Count = g.Count(),
TotalQty = g.Sum(n => n.Qty),
Price = g.Average(n => n.Price)
};
also tried
var ProductUsageSummary = from b in myProductUsage
group b by b.Period b.ProductCode into g
select new
{
Period = g.Key(n => n.period),
Code = g.Key,
Count = g.Count(),
TotalQty = g.Sum(n => n.Qty),
Price = g.Average(n => n.Price)
};
You could create an anonymouns object to to group on multiple columns (ex... new {prop1 prop2}) , and the grouped fields can be accessed by Key.PropertyName
Try this.
var ProductUsageSummary = from b in myProductUsage
group b by new { b.Period, b.ProductCode }into g
select new
{
Period= g.Key.Period,
Code = g.Key.ProductCode ,
Count = g.Count(),
TotalQty = g.Sum(n => n.Qty),
Price = g.Average(n => n.Price)
};
This is the correct syntax using Anonymous Types :
group b by new { b.ProductCode, b.Period } into g
Then in select:
g.Key.ProductCode and g.Key.Period
Full Query:
var ProductUsageSummary = from b in myProductUsage
group b by new { b.Period b.ProductCode } into g
select new
{
Period = g.Key.Period,
Code = g.Key.ProductCode,
Count = g.Count(),
TotalQty = g.Sum(n => n.Qty),
Price = g.Average(n => n.Price)
};

LINQ Query for GroupBy and Max in a Single Query

I have the following LINQ query but i want to modify it that I want to group by staffId and pick only those records whose ObservationDate is Max for each staffId.
from ob in db.TDTObservations.OfType<TDTSpeedObservation>()
select new
{
Id = ob.ID,
AcademicYearId = ob.Teachers.FirstOrDefault().Classes.FirstOrDefault().AcademicYearID,
observationDate = ob.ObservationDate,
schoolId = ob.Teachers.FirstOrDefault().Classes.FirstOrDefault().SchoolID,
staffId=ob.Teachers.FirstOrDefault().ID
};
var observations =
from ob in db.TDTObservations.OfType<TDTSpeedObservation>()
select new {
Id = ob.ID,
AcademicYearId = ob.Teachers.FirstOrDefault().Classes.FirstOrDefault().AcademicYearID,
observationDate = ob.ObservationDate,
schoolId = ob.Teachers.FirstOrDefault().Classes.FirstOrDefault().SchoolID,
staffId=ob.Teachers.FirstOrDefault().ID
};
var result = from o in observations
group o by o.staffId into g
select g.OrderByDescending(x => x.observationDate).First();
what about this: hereby you first group your entries (Teachers) by their ID together and then from each group (grp) you pick that one with the latest ObservationDate
var observations = from d in db.TDTObservations.OfType<TDTSpeedObservation>()
group d by d.Teachers.FirstOrDefault().ID into grp
select grp.OrderByDescending(g => g.ObservationDate).FirstOrDefault();

How to find same values in a list column and concatenating strings on the other rows for the same column value

I have a List with 2 columns with the following structure:
50 process:3333
50 phone:xxxx
51 process:2222
51 phone:yyyy
I need to build a new list based on that first one with this structure:
50 process:3333,phone:xxxx
51 process:2222,phone:yyyy
Does List have any method to find from one column a same value and concatenate the string on second column.
Or I have to find a way to do it manually using a foreach or a while statement?
Assuming a simple struct like...
public struct Proc
{
public int ID { get; set; }
public string Value { get; set; }
}
with your sample data:
var procList = new List<Proc>() {
new Proc{ID=50,Value="process:3333"},new Proc{ID=50,Value="phone:xxxx"},
new Proc{ID=51,Value="process:2222"},new Proc{ID=51,Value="phone:yyyy"},
};
You can use Enumerable.GroupBy and String.Join:
var procIdGroupList = procList
.GroupBy(p => p.ID)
.Select(g => new Proc
{
ID = g.Key,
Value = string.Join(",", g.Select(p => p.Value))
}).ToList();
DEMO
Found a workaround for that:
//Recupera valores dos indices para o tipo de documento
List<Gedi.Models.OperacoesModel.imports> valuesList = new List<Gedi.Models.OperacoesModel.imports>();
var valuesListObj = from a in context.sistema_Documentos
join b in context.sistema_Indexacao on a.id equals b.idDocumento
join c in context.sistema_Indexes on b.idIndice equals c.id
where a.ativo == 1
select new
{
id = a.id,
values = c.idName + ":" + b.valor
};
var çist = (from x in valuesListObj.AsEnumerable()
select new Gedi.Models.OperacoesModel.imports
{
id = x.id,
values = x.values
}).ToList();
var importList = çist.GroupBy(p => p.id).Select(g => new Gedi.Models.OperacoesModel.imports
{
id = g.Key,
values = string.Join(",", g.Select(p => p.values))
}).ToList();

LINQ Query to count by distinct category / subcategory

I have a table, generated from a LINQ query on a datatable, which has subcategory and category fields:
Name...........Category.........Subcategory
Kiss...........Rock.............Glam Rock
Metallica......Rock.............Hard Rock
Bon Jovi.......Rock.............Soft Rock
Slade..........Rock.............Glam Rock
Meatloaf.......Rock.............Soft Rock
Wilee..........Dance............Grime
Mgmt...........Dance............Nu Rave
Dizee..........Dance............Grime
The LINQ query I am using to generate this table is:
var qCategory = from c in dtCategory.AsEnumerable()
select new {
Artist = c.Field<string>("Artist"),
Category = c.Field<string>("Category"),
Subcategory = c.Field<string>("Subcategory")
};
Now I want to get a count of each category/subcategory pair. e.g. for the above example I want to return:
Category............Subcategory.......Count
Rock................Glam Rock.........2
Rock................Soft Rock........2
Rock................Hard Rock.........1
Dance...............Grime.............2
Dance...............Nu Rave...........1
How can I acheive this?
Try:
var counts = from artist in qCategory
group artist by new { artist.Category, artist.Subcategory }
into g
select new {
g.Key.Category,
g.Key.Subcategory,
Count = g.Count()
};
If you want to enforce that subcategories always have the same parent category (given that the sub-categories are named "Glam Rock" etc., I assume that this is in fact the case), do:
var counts = from artist in qCategory
group artist by artist.Subcategory into g
select new {
Category = g.Select(a => a.Category)
.Distinct()
.Single(),
Subcategory = g.Key,
Count = g.Count()
};
This will throw an exception if "Rap Rock" turns up as a subcategory of both "Rap" and "Rock".
qCategory.
GroupBy(item => new {Category = item.Category, Subcategory = item.Subcategory}).
Select(group => new {Category = group.Key.Category, Subcategory = group.Key.Subcategory, Count = group.Count()})

Categories

Resources