Linq multi level grouping - linq

I am trying to implement a multi level grouping in linq
In sql it would be something like that.
Select VarId, variable, UT ,
(case when resultat >= 0 then sum(resultat) else 0) as Positive,
(case when resultat < 0 then sum(resultat) else 0) as Negatif
from
(Select VarId, variable, UT , valeur, sum( resultat ) from IndicRow
group by VarId, variable, UT , valeur)
group by VarId, variable, UT
i have created that in linq but i can't find the way to group on the result of a group by
var Chartline = from IndicRow in Indic_dt.AsEnumerable()
//where SelTradeId.Contains(IndicRow.Field<int>("TradeNum"))
group IndicRow by new
{
GpVariable = IndicRow.Field<string>("Variable"),
GpUT = IndicRow.Field<string>("UT"),
GPVarId = IndicRow.Field<int>("VarId"),
GPValue = IndicRow.Field<double>("Valeur")
} into RdVal
select new
{
VarId = RdVal.Key.GPVarId,
Variable = RdVal.Key.GpVariable,
UT = RdVal.Key.GpUT,
Valeur = RdVal.Key.GPValue,
Resultat = RdVal.Sum(IndicRow => IndicRow.Field<double>("Resultat_EuroNet"))
};
The final goal is to obtain a 5 columns Datatable (VarId, variable, UT, Positive, negative)

The general pattern fro a two-level grouping is
from t in Mains
group t by t.GroupProperty1 into mainGroup
select new { mainGroup.Key,
MainCount = mainGroup.Count(),
subGroups = from mg in mainGroup
group mg by mg.GroupProperty2 into subGroup
select new { subGroup.Key,
SubCount = subGroup.Count()
}
}
So the main grouping is by VarId, variable, UT and the sub grouping only by valeur, because the sub group only contains items of one main group.

Related

How to group by multiple columns with joins using linq

How to group by multiple columns coming from different tables and finally sum the amount column
var result = _employeeDAL.GetList(db =>
from es in db.Set<EmployeeSchedule>()
join est in db.Set<EmployeeSalaryType>() on est.Employee_Id equals es.Employee_Id
join et in db.Set<EmployeeType>() on est.Employee_Salary_Id equals et.Employee_Salary_Id
where es.Status == "JOINED" && es.JoinedDate.Year == 2017
select new
{
EmployeeName = es.EmployeeName
,Amount = est.Amount ///----------> SUM THIS
,EmployeeType = et.EmployeeType
});
Here's WHat I have tried
var result = _employeeDAL.GetList(db =>
from es in db.Set<EmployeeSchedule>()
join est in db.Set<EmployeeSalaryType>() on est.Employee_Id equals es.Employee_Id
join et in db.Set<EmployeeType>() on est.Employee_Salary_Id equals et.Employee_Salary_Id
group new { es, est, et } by new { es.EmployeeName, et.EmployeeType } into grp
where es.Status == "JOINED" && es.JoinedDate.Year == 2017
select new
{
EmployeeName = es.EmployeeName
,Amount = grp.Sum(g=>g.est.Amount)
,EmployeeType = et.EmployeeType
});
You are almost there. Just need to take into account that after the group ... by ... into grp clause the only variable in scope is grp.
So move the where clause before the group by and use grp.Key inside the select:
var result = _employeeDAL.GetList(db =>
from es in db.Set<EmployeeSchedule>()
join est in db.Set<EmployeeSalaryType>() on est.Employee_Id equals es.Employee_Id
join et in db.Set<EmployeeType>() on est.Employee_Salary_Id equals et.Employee_Salary_Id
where es.Status == "JOINED" && es.JoinedDate.Year == 2017
group new { es, est, et } by new { es.EmployeeName, et.EmployeeType } into grp
select new
{
EmployeeName = grp.Key.EmployeeName,
Amount = grp.Sum(g => g.est.Amount),
EmployeeType = grp.Key.EmployeeType,
});

how use multiple join in linq?

var abc1 = from dlist in db.DebtorTransactions.ToList()
join war in db.Warranties on dlist.ProductID equals war.Id
join ag in db.Agents on war.fldAgentID equals ag.pkfAgentID
join sr in db.SalesReps on war.fldSrId equals sr.pkfSrID
where dlist.TransTypeID == 1
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt1 = abc1.Sum(x => x.Key.Amount);
var abc2 = from dlist in db.DebtorTransactions.ToList()
join cjt in db.CarJackaTrackas on dlist.ProductID equals cjt.pkfCjtID
join ag in db.Agents on cjt.AgentID equals ag.pkfAgentID
join sr in db.SalesReps on cjt.SalesRepId equals sr.pkfSrID
where dlist.TransTypeID == 0
select new
{
dlist.Amount,
dlist.TransTypeID,
name = ag.Name,
ag.pkfAgentID,
sr.pkfSrID,
enter code here` salesnam = sr.Name
} into objabc
group objabc by new
{
objabc.TransTypeID,
objabc.name,
objabc.salesnam,
objabc.Amount
};
var amt2 = abc1.Sum(x => x.Key.Amount);
//var result1=
return View();
i am new to linq, this query is working but i need to get the sum of Amount where dlist.TransTypeID == 0 and where dlist.TransTypeID == 1 by just single query. may anybody help me? thanks in advance
Here's a trimmed down example of how you can do it. You can add the joins if they are necessary, but I'm not clear on why you need some of the extra join values.
var transTypeAmountSums = (from dlist in db.DebtorTransactions
group dlist by dlist.TransTypeId into g
where g.Key == 0 || g.Key == 1
select new
{
TransTypeId = g.Key,
AmountSum = g.Sum(d => d.Amount)
}).ToDictionary(k => k.TransTypeId, v => v.AmountSum);
int transTypeZeroSum = transTypeAmountSums[0];
int transTypeOneSum = transTypeAmountSums[1];
A couple of things to note:
I removed ToList(). Unless you want to bring ALL DebtorTransactions into memory then run a Linq operation on those results, you'll want to leave that out and let SQL take care of the aggregation (it's much better at it than C#).
I grouped by dlist.TransTypeId only. You can still group by more fields if you need that, but it was unclear in the example why they were needed so I just made a simplified example.

Linq grouping and projection query

I have a EF "Call" class which has a date, telephone number, caller name, and call cost.
My aim is to group the calls by the telephone number, and sum the total cost, and take the results of the 40 most expensive calls. I have all of this working, but I am having trouble with the projection, how do I get access to caller name?
var query =
(
from call in model.Calls
group call by call.TelephoneNumber into g
orderby g.Sum(gr => gr.ActualCost) descending
select new
{
TelephoneNumber = g.Key,
CallerName = ???
Cost = (g.Sum(gr => gr.ActualCost)),
TotalNumbers = g.Count(),
}
).Take(40);
You need group on the CallerName also:
var query =
(from call in model.Calls
group call by new { call.TelephoneNumber, call.CallerName } into g
orderby g.Sum(gr => gr.ActualCost) descending
select new
{
TelephoneNumber = g.Key.TelephoneNumber,
CallerName = g.Key.CallerName,
Cost = (g.Sum(gr => gr.ActualCost)),
TotalNumbers = g.Count(),
}).Take(40);

How to join two datasource which return all rows and group by condition?

I have a problem when using LINQ to join two datasource. Two datasource created by a query like :
var A = (from....
group .... into grp
select new
{
Qty = grp.Count(),
Code = grp.Key.Code,
Name = grp.Key.Name
});
var B = (from....
group .... into grp
select new
{
Qty = grp.Count(),
Code = grp.Key.ContCode,
Name = grp.Key.ContName
});
Value of 'A' will be returned like this :
Qty-Code-Name
1-10A-Cont10
1-20B-Cont20
1-30C-Cont30
Value of 'B' will be returned like this :
Qty-Code-Name
1-10A-Cont10
1-20B-Cont20
1-30C-Cont30
1-40D-Cont40
1-50E-Cont50
I want to join A and B (or do somethings) and the result like this (which sum column 'Qty' if they have the same 'Code' and 'Name') :
Qty-Code-Name
2-10A-Cont10
2-20B-Cont20
2-30C-Cont30
1-40D-Cont40
1-50E-Cont50
How can I do it ? Please help me.
Thank you very much !
Concat the two datasources and than group by code and name.
Something like:
var q = from v in A.Concat(B)
group v by new {v.Code,v.Name } into g
select new
{
Qty = g.Sum(a => a.Qty),
CodeName = g.Key.Code,
Name = g.Key.Name
};

Linq extract a count() value from a data object

I have divAssignments that has potential multiple rows by rNI, an official id, according to a compound key of Indictment and booking numbers.
rNI Booking Indictment
12345 954445 10 12345
12345 954445 10 12346
12345 954445 10 12347
So ID has a count of 3 for a single booking number for this rni.
I get lost attempting to generate a count and a group by booking Number:
var moreThen = from dA in divAssignments
select new { dA.rNI, IndictmentCount = dA.indictmentNumber.Count() };
Most of the examples are dealing with static int[] and don't seem to work in my case.
How do I get a group and then a count? If I could put in a having that would be fantastic.
from a t-sql POV I'd use this:
Select rni, bookingNumber, count(*) IndictmentCount
from divAssignments
group by rni, bookingNumber
having count(*) > 0
TIA
How about something like this:
var query = from item in divAssignments
group item by item.rNI into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
If you're interested in grouping by both the rNI and the booking number, I would change it to this:
var query = from item in divAssignements
group item by new { item.rNI, a.Booking } into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count
};
OR
var query = from item in divAssignments
group item by item into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
and implement IEquatable on the divAssignment object to support equality comparison. The other option if you'd like is to write an IEqualityComparer instance to do the composite key comparison. Your query could then look like:
var query =
divAssignments
.GroupBy(i => i, new MyCustomEqualityComparer())
.Select(i => new { Key = i.Key, Count = i.Count());
var query =
from dA in divAssignments
group dA by new { dA.rNI, dA.bookingNumber };
foreach(var grp in query)
{
Console.WriteLine("rNI={0}, bookingNumber={1} => Count={2}", grp.Key.rNI, grp.Key.bookingNumber, grp.Count());
}
If you use a Grouping operator in Linq you will get what you need. The code:
var count = from a in divAssignments
group a by new { a.rNI, a.Booking } into b
select b;
will return a collection of IGrouping objects. This will give you the Key (in my example this will be an anonymous type with an rNI and a Booking property) and a collection of the divAssignments that match the key.
Using Method syntax (much easier to read in my opinion):
First group the records, then select a new result for each group that contains the count.
var groups = divAssignments.GroupBy(d => new { d.rNI, d.Booking });
groups.Select(g=> new { g.Key.rNI, g.Key.Booking, IndictmentCount = g.Count() });

Resources