How to get a sum of children values on one LINQ - c#

This is the structure I have:
Program
- Description, etc...
Action
- Program_Id, Description, etc..
Cost
- Action_Id, Value1, Value2, Value3
One Action can Have multiple Costs.
What I Need is a query that group this values by Program. Like:
"Program name" | Total of Value1 | Total of Value 2 | Total of the program
This is my effort so far:
var ListByPrograma = from a in db.Actions
join c in db.Costs on a.Id equals c.Action_Id
group a by a.Program into p
select new
{
Program = p.Key,
actionsQuantity = p.Count(),
totalValue1 = p.Costs.????
totalValue2 = ?,
totalByProgram = ?
};

Does something like this work?
var ListByPrograma = from a in db.Actions
join c in db.Costs on a.ID equals c.Action_Id
group new {a,c} by a.Program into p
select new
{
Program = p.Key,
actionsQty = p.Count ( ),
totalValue1 = p.Sum(y => y.c.Value1),
totalValue2 = p.Sum (y => y.c.Value2),
totalValue3 = p.Sum(y=>y.c.Value3)
};

Related

LINQ Query - Wrong Count Value

I am working with some SQL that has been provided and I am running into an issue where the count in the LINQ is different from the count in the SQL and would appreciate some help if possible.
The original SQL that was given is pretty poorly arranged and has a large number of nested queries. This being one of them. I have broken the query down into its main component and am now stitching it back together with LINQ.
The SQL that I am working with is here :
DECLARE #QSCollectionId UNIQUEIDENTIFIER = 'f52ec043-b360-4266-f95f-08d7c66074pe';
SELECT fieldid
Count(fieldid) AS fieldcount,
Sum(CASE
WHEN answer = [value] AND Answer IS NOT NULL THEN 1
ELSE 0
END) AS FieldAnswerMatchCount
FROM (SELECT DISTINCT FCI.fieldid,
answer,
QSA.qsrid,
FAG.fieldid AS dependentfield,
FAG.value
FROM forms.fieldconstraints FCI
INNER JOIN forms.sectionfieldmappings SFM
ON FCI.fieldid = SFM.fieldid
INNER JOIN forms.qssectionmappings QSSM
ON SFM.sectionid = QSSM.sectionid
INNER JOIN sessions.qsr
ON QSSM.qsid = qsr.qsid
--AND Qsr.QSCollectionId=#QSCollectionId
LEFT JOIN forms.answerguides FAG
ON
FCI.dependantanswerguideid = FAG.answerguideid
LEFT JOIN sessions.qsranswers QSA
ON FAG.fieldid = QSA.fieldid
AND Qsr.QsrId = QSA.qsrid
) AS
FieldConstr
GROUP BY fieldid
The LINQ
var id = Guid.Parse("f52ec043-b360-4266-f95f-08d7c66074be");
var firstResultPartThree = (from fci in FieldConstraints
join sfm in SectionFieldMappings on fci.FieldId equals sfm.FieldId
join qssm in QSSectionMappings on sfm.SectionId equals qssm.SectionId
join qsr in QSRs on new { qssm.QSId } equals new { qsr.QSId }
join ag in AnswerGuides on fci.DependantAnswerGuideId equals ag.AnswerGuideId into agResult
from agJoin in agResult.DefaultIfEmpty()
join qsrAnswers in QSRAnswers on new { agJoin.FieldId, qsr.QsrId } equals new {qsrAnswers.FieldId, qsrAnswers.QsrId} into qsrAnswersResult
from qsrAnswersJoin in qsrAnswersResult.DefaultIfEmpty()
//where qsr.QSCollectionId == id
select new {
FieldId = fci.FieldId,
Answer = qsrAnswersJoin.Answer,
QsrId = (Guid?)qsrAnswersJoin.QsrId,
DependentFieldId = agJoin.FieldId,
Value = agJoin.Value
}
);
firstResultPartThree.Dump();
var firstResultPartTwo = (from fr in firstResultPartThree
where fr.FieldId == Guid.Parse("98CA6B6F-4070-4CEB-E9F1-08D7C66278F9")
group fr by fr.FieldId into grp
select new {
FieldId = grp.Key,
Fieldcount = grp.Count(),
FieldAnswerMatchCount = grp.Count(x => (Guid?)grp.Key.Value != null)
}
);
The result of the LINQ in the example below gives me
FieldId | fieldcount | FieldAnswerMatchCount
98ca6b6f-4070-4ceb-e9f1-08d7c66278f9 | 4 | 4 |
The result of the sql for the same data is
98ca6b6f-4070-4ceb-e9f1-08d7c66278f9 | 3 | 2 |
The area that I am struggling with is
select new {
FieldId = grp.Key,
Fieldcount = grp.Count(),
FieldAnswerMatchCount = grp.Count(x => (Guid?)grp.Key.Value != null)
I understand that the count in the select is wrong, however I do not know how I need to correct it and would be grateful for some help.

LINQ Group By Join

I'm struggling with what is a rather simple SQL select statement. How can this be translated into LINQ?
select
o.IdOrder, Date, s.suma, name, adresa
from
Clients c
join
Orders o on (c.IdClient = o.IdClient)
join
(select IdOrder, sum(price) suma
from OrderProduct
group by IdOrder) s on (o.IdOrder = s.IdOrder);
If you could point me in the right direction, I would greatly appreciate it.
This is what I have so far:
var y = from w in db.OrderProducts
group w by w.IdOrder into TotaledOrder
select new
{
IdOrder = TotaledOrder.Key,
price = TotaledOrder.Sum(s => s.price)
};
var i = 0;
var cc = new dynamic[100];
foreach (var item in y)
{
cc[i++] = db.Orders.Where(t => t.IdOrder == item.IdOrder)
.Select(p => new
{
IdOrder = item.IdOrder,
price = item.price,
}).Single();
}
Your SQL doesn't really give an idea on your underlying structure. By a guess on column names:
var result = from o in db.Orders
select new {
IDOrder = o.IDOrder,
Date = o.Date,
Suma = o.OrderProduct.Sum( op => op.Price),
Name = o.Client.Name,
Adresa = o.Client.Adresa
};
(I have no idea what you meant by the loop in your code.)

Query tree structure

I'm working with EntityFramework but can use other ways if need be
Here's the case: I have an SQL Server Database with a scheme similar to:
A B C AhasB AhasC
________ ________ ________ __________ ___________
AId BId CId AId AId
... Btxt Ctxt BId CId
BParent ...
...
Where ... means other columns not important to the problem.
Tables C and AhasC are there to keep data during a lengthy process and are cleared on process completion, so i always start with both empty
Now, the process get's a lot of data (1000+ records) from online sources and stores it in C. After C is filled, I want to fill table AhasC based on the following:
INSERT INTO C (AId, CId) VALUES (
SELECT A.AId, C.CId
FROM A, B, C, AhasB
WHERE A.AId = AhasB.AId AND B.BId = AhasB.BId AND
C.CTxt IN (
SELECT D.BTxt
FROM B AS D
WHERE D.BId = B.BId OR ??
)
)
Before i explain what i need in ?? let me run through what i have here:
I want to insert into table AhasC the pair A.AId, C.CId, so that in all pairs, C.CTxt is the same as a B.Btxt that is connected to A in AhasB.
Moreover (and here enters the ??) i also want it to match the B.Btxt of any parent of B.
Example:
A B
_______ ____________________________________
AId = 1 BId = 1, BTxt = 'a', BParent = Null
AId = 2 BId = 2, BTxt = 'b', BParent = 1
AId = 3 Bid = 3, BTxt = 'c', BParent = 2
AId = 4 BId = 4, BTxt = 'x', BParent = Null
C AahsB
_____________________ _________
CId = 1, Ctxt = 'b' AId = 1, BId = 3
CId = 2, CTxt = 'z' AId = 3, BId = 4
This should result in:
AhasC
____________
AId = 1, CId = 1
So again, AhasC must connect A and C if A is connected to a B that either has BTxt equal to CTxt, or who's parent (or grand-parent and so on) has a BTxt that is the same as CTxt.
Hope i didn't overcomplicate my explaining here :p
EDIT1: as per #dotctor's coments, here's an image of my real shema (not that i think it will add much to the question)
A = Contatos
B = Termos
C = ConcursosPublicos
AhasB = TermosContatos
AhasC = ConcursosContatos
A.AId = Contatos.Id
B.BId = Termos.Id
C.CId = ConcursosPublicos.Id
B.BTxt = Termos.Area
C.CTxt = ConcursosPublicos.Area
B.BParent = Termos.Pai
And here's my real code doing this work presently:
public static void Connect(ProgressBar progress)
{
lock (Locker)
using (var ctx = new ConcursosContainer())
{
int i = 0;
IList<Contatos> contatos = ctx.Contatos.ToList();
progress.Invoke((MethodInvoker) (() =>
{
progress.Value = 0;
progress.Maximum = contatos.Count;
}));
foreach (Contatos contato in contatos)
{
Console.WriteLine(contato.Id);
List<Termos> tree = GetTree(ctx, contato.Id).SelectMany(x => x.ToArray()).ToList();
List<int> attr = ctx.ConcursosContatos.Where(x => x.ContatoId == contato.Id).Select(x => x.ConcursoId).ToList();
IList<ConcursosPublicos> concursosPublicos = ctx.ConcursosPublicos.Where(x => !attr.Contains(x.Id)).ToList();
foreach (ConcursosPublicos concursosPublico in concursosPublicos)
{
if (tree.Any(termo => (termo.Tipo == concursosPublico.TipoConc) && concursosPublico.Area.Trim().EndsWith(termo.Area)))
{
ctx.ConcursosContatos.Add(new ConcursosContatos
{
ContatoId = contato.Id,
ConcursoId = concursosPublico.Id
});
i++;
}
if (i == 9)
{
ctx.SaveChanges();
i = 0;
}
}
progress.Invoke((MethodInvoker) (progress.PerformStep));
}
if (i > 0)
ctx.SaveChanges();
}
}
private static IEnumerable<Stack<Termos>> GetTree(ConcursosContainer ctx, int id)
{
var res = new List<Stack<Termos>>();
IQueryable<Termos> terms = ctx.Termos.Where(x => ctx.TermosContatos.Any(y => (y.ContatoId == id) && (y.TermoId == x.Id)));
foreach (Termos term in terms)
{
var stack = new Stack<Termos>();
if (term.Pai.HasValue)
AddParent(ctx, stack, term);
stack.Push(term);
res.Add(stack);
}
return res;
}
private static void AddParent(ConcursosContainer ctx, Stack<Termos> stack, Termos term)
{
Termos pai = ctx.Termos.First(x => x.Id == term.Pai.Value);
if (pai.Pai.HasValue)
AddParent(ctx, stack, pai);
stack.Push(pai);
}
This code does the job but for 1000+ members of ConcursosPublicos and 7000+ members of Contatos (with contatos on way to grow in the future) it can take between 15 to 20 hours to complete. Since this a daily process i need a more efficient way to fill in ConcursosContatos
You need some recursion to get the family tree on your B table. In SQL Server you can do this with a CTE:
;with chld as (
select B.BId, B.BTxt, B.BParent
from dbo.B as B
union all
select chld.BId , b1.BTxt, b1.BParent
from dbo.B as B1
inner join chld
on B1.BId = chld.BParent
)
select BId, BTxt from chld option(maxrecursion 32767)
The result set:
BId BTxt
1 a
2 b
3 c
4 x
3 b
3 a
2 a
If this isn't correct, no need to go any further. Otherwise, you can join this to the other tables as needed to populate your AhasC table.

SQL to Linq select multiple columns in group by

I would like to convert a SQL statement to LINQ but i have some problems doing it.
The sql statement is :
SELECT
C.[Call_Date], CC.[Company], R.Resolution,
COUNT_BIG(*) AS CNT,
SUM([Duration]) AS Total
FROM
[Calls] C
Join
[CompanyCharges] CC on [Company_Charge] = [CompanyCharge]
Join
[Resolutions] R on C.Call_Resolution = R.Resolution
where
Call_Date >= '05/29/2013'
Group By
C.[Call_Date], CC.[Company], CC.[CompanyCharge], R.Resolution, R.Resolution_Order
I wrote something like :
var stats = from c in dbContext.Calls
join cc in dbContext.CompanyCharges on c.Company_Charge equals cc.CompanyCharge
join r in dbContext.Resolutions on c.Call_Resolution equals r.Resolution
where (c.Call_Date > "05/29/2013")
group new { c, cc, r } by new { c.Call_Date, cc.CompanyCharge, r.Resolution, r.Resolution_Order } into statsGroup
select new { Count = statsGroup.Count(), ??? };
I managed to count the elements, but i need a sum[duration] and some columns from different tables.
Please share your wisdome with me.
Assuming that the [Duration] field is part of the [Calls] table:
var stats = /* ... */
select new
{
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};
You'd probably want to include your grouping fields in the new anonymous type as well:
var stats = /* ... */
select new
{
Call_Date = statsGroup.Key.c.Call_Date,
CompanyCharge = statsGroup.Key.cc.CompanyCharge,
Resolution = statsGroup.Key.r.Resolution,
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};

Use LINQ to group data from DataTable

I want to use LINQ to group data from a DataTable (columns: userid, chargetag, charge).
The content could look like this:
userid chargetag charge
-----------------------------
user1 tag3 100
user2 tag3 100
user3 tag5 250
I need something like this as a result:
chargetag count sum
-------------------------
tag3 2 200
tag5 1 250
This is what I have so far:
var groupedData = from b in dataTable.AsEnumerable()
group b by b.Field<string>("chargetag") into g
let count = g.Count()
select new
{
ChargeTag = g.Key,
Count = count,
};
I can extract the name of the chargetag and the number of it.
How would I have to change the LINQ query to access the sum of charges as well?
Thanks in advance :-)
Regards,
Kevin
That's pretty easy - just use the Sum extension method on the group.
var groupedData = from b in dataTable.AsEnumerable()
group b by b.Field<string>("chargetag") into g
select new
{
ChargeTag = g.Key,
Count = g.Count(),
ChargeSum = g.Sum(x => x.Field<int>("charge"))
};
(I've removed the let clause here as it wasn't really buying you anything.)
Now that may be inefficient; it may end up grouping twice in order to perform two aggregation operations. You could fix that like with a query continuation like this, if you really wanted:
var groupedData = from b in dataTable.AsEnumerable()
group b by b.Field<string>("chargetag") into g
select new
{
ChargeTag = g.Key,
List = g.ToList(),
} into g
select new
{
g.ChargeTag,
Count = g.List.Count,
ChargeSum = g.List.Sum(x => x.Field<int>("charge"))
};
Or with a let clause instead:
var groupedData = from b in dataTable.AsEnumerable()
group b by b.Field<string>("chargetag") into g
let list = g.ToList()
select new
{
ChargeTag = g.Key,
Count = list.Count,
ChargeSum = list.Sum(x => x.Field<int>("charge"))
};

Categories