How can I group by multiple columns using linq projection?
Something like this:
var q = db.Areas.GroupBy(x => x.AreaCatId, x.AreaCatName, x.AreaId, x.AreaName);
Resulting in a flat result set such as:
AreaCatId, AreaCatName, AreaId, AreaName
0 US 1 FL
0 US 2 NY
1 Canada 3 BC
You can GroupBy an anonymous type:
var q = db.Areas.GroupBy(
x => new
{
CatId = x.AreaCatId,
CatName = x.AreaCatName,
Id = x.AreaId,
Name = x.AreaName
});
Related
I am trying to join two datatables using linq
var invoices420 = dt420_.AsEnumerable();
var invoices430 = dt430_.AsEnumerable();
var query = from inv430 in invoices430
join inv420 in invoices420 on inv430.LinkDoc equals inv420.LinkDoc
orderby inv430.SID
select new
{
LinkDoc = inv430.LinkDoc,
TotalIn = Math.Round(inv430.Credit, 2),
TotalOut = ((inv420 == null) ? 0 : Math.Round(inv420.Debit, 2))
};
Joining does not seems to be a problem, but I am getting an error'System.Data.DataRow' does not contain a definition for 'LinkDoc' and no extension method 'LinkDoc' accepting a first argument of type 'System.Data.DataRow' could be found (are you missing a using directive or an assembly reference?).
What do I have to do to reference a column in DataTable for example inv430.LinkDoc without using inv430.Field("linkdoc")?
If I want to do a group by on result set I am thinking
var q2 = query
.GroupBy(item => item.LinkDoc);
return q2.ToArray();
Problem is that in q2 I dont get all the columns (linkdoc, totalin, totalout).
Original data is
dt420_
Linkdoc Credit
Invoice1 500
Invoice2 100
Invoice3 200
dt430_
LinkDoc Debit
Invoice1 100
Invoice1 100
Invoice2 200
Result would be
LinkDoc TotalIn(Credit) TotalOut(Debit)
Invoice1 500 200
Invoice2 100 200
Invoice3 200 0
You need to replace all places you called directly to properties like
inv430.LinkDoc
to
inv430["LinkDoc"]
inv430 is a DataRow so you need to use the indexer that gets a string.
EDIT:
Your join will bring wrong data (see my comment below). You need to use this code:
var group430 = from inv430 in invoices430
group inv430 by inv430["LinkDoc"].ToString().Trim() into g
select new
{
LinkDoc = g.Key.ToString().Trim(),
TotalOut = g.Sum(inv => Math.Round((decimal)inv["Debit"], 2))
};
var group420 = from inv420 in invoices420
group inv420 by inv420["LinkDoc"].ToString().Trim() into g
select new
{
LinkDoc = g.Key.ToString().Trim(),
TotalIn = g.Sum(inv => Math.Round((decimal)inv["Credit"], 2))
};
var result = from inv430 in group430
join inv420 in group420 on inv430.LinkDoc equals inv420.LinkDoc into inv
from inv420 in inv.DefaultIfEmpty()
select new
{
inv430.LinkDoc,
TotalOut = inv430.TotalOut,
TotalIn = inv420 != null ? inv420.TotalIn : 0
};
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
};
I have a linq statement which calls a stored proc and returns a list of items and descriptions.
Like so;
var q = from i in doh.usp_Report_PLC()
where i.QTYGood == 0
orderby i.PartNumber
select new Parts() { PartNumber = i.PartNumber, Description = i.Descritpion.TrimEnd() };
I then have another SQL statement which returns the quantities on order and delivery date for each of those items. The Parts class has two other properties to store these. How do I update the existing Parts list with the other two values so that there is one Parts list with all four values?
UPDATE
The following code now brings out results.
var a = from a1 in db.usp_Optos_DaysOnHand_Report_PLC()
where a1.QTYGood == 0
orderby a1.PartNumber
select new Parts() { PartNumber = a1.PartNumber, Description = a1.Descritpion.TrimEnd() };
var b = from b1 in db.POP10110s
join b2 in db.IV00101s on b1.ITEMNMBR equals b2.ITEMNMBR
//from b3 in j1.DefaultIfEmpty()
where b1.POLNESTA == 2 && b1.QTYCANCE == 0
group b1 by new { itemNumber = b2.ITMGEDSC } into g
select new Parts() { PartNumber = g.Key.itemNumber.TrimEnd(), QtyOnOrder = g.Sum(x => Convert.ToInt32(x.QTYORDER)), DeliveryDue = g.Max(x => x.REQDATE).ToShortDateString() };
var joinedList = a.Join(b,
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
QtyOnOrder = oss.QtyOnOrder,
DeliveryDue = oss.DeliveryDue
});
return joinedList.ToList();
Assuming your "other SQL statement" returns PartNumber, Quantity and DeliveryDate, you can join the lists into one:
var joinedList = q.Join(OtherSQLStatement(),
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
Quantity = oss.Quantity,
DeliveryDate = oss.DeliveryDate
}).ToList();
You can actually combine the queries and do this in one join and projection:
var joinedList = doh.usp_Report_PLC().
Where(i => i.QTYGood == 0).
OrderBy(i => i.PartNumber).
Join(OtherSQLStatement(),
i => i.PartNumber,
o => o.PartNumber,
(i, o) =>
new Parts
{
PartNumber = i.PartNumber,
Description = i.Description,
Quantity = o.Quantity,
DeliveryDate = o.DeliveryDate
}).ToList();
And again: I assume you have PartNumber in both returned collections to identify which item belongs to which.
Edit
In this case the LINQ Query syntax would probably be more readable:
var joinedList = from aElem in a
join bElem in b
on aElem.PartNumber equals bElem.PartNumber into joinedAB
from abElem in joinedAB.DefaultIfEmpty()
select new Part
{
PartNumber = aElem.PartNumber,
Description = aElem.Description,
DeliveryDue = abElem == null ? null : abElem.DeliveryDue,
QtyOnOrder = abElem == null ? null : abElem.QtyOnOrder
};
Your DeliveryDue and QtyOnOrder are probably nullable. If not, replace the nulls by your default values. E.g. if you don't have the element in b and want QtyOnOrder to be 0 in the resulting list, change the line to
QtyOnOrder = abElem == null ? 0 : abElem.QtyOnOrder
HI there I am hoping for some help with a query I have.
I have this query
var group =
from r in CustomerItem
group r by r.StoreItemID into g
select new { StoreItemID = g.Key,
ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
I am returning my results to a list so I can bind it listbox.
I have a property called EntryType which is an int. There are 2 available numbers 1 or 2
Lets say I had 3 items that my query is working with
2 of them had the EntryType = 1 and the 3rd had EntryType2. The first records had a ItemAmount of 55.00 and the 3rd had a ItemAmount of 50.00
How can I group using something simlar to above but minus the ItemAmount of 50.00 from the grouped amount to return 60.00?
Any help would be great!!
It's not really clear what the question is - are you just trying to ignore all items with an entry type of 2? To put it another way, you only want to keep entries with an entry type of 1? If so, just add a where clause:
var group = from r in CustomerItem
where r.EntryType == 1
group r by r.StoreItemID into g
select new {
StoreItemID = g.Key, ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
Change ItemAmount = ... to:
ItemAmount =
g.Where(x => x.EntryType == 1).Sum(cr => cr.ItemAmount) -
g.Where(x => x.EntryType == 2).Sum(cr => cr.ItemAmount),
I changed Customer to g because this seems to be an error, but it's not clear to me from your question what you mean here, so maybe this change is not what you want.
A slightly more concise method is to use test the entry type in the sum and use the ternary operator to choose whether to add the positive or negative value:
ItemAmount = g.Sum(cr => cr.EntryType == 1 ? cr.ItemAmount : -cr.ItemAmount),
This gives the value of 60.00 as you required.
Crazy question...however, I want the sum of all the rows in a table for a column (without using the group by clause)
Example:
Table = Survey
Columns = Answer1, Answer2, Answer3
1 1 1
4 3 5
3 3 2
I want the sums for each column.
Final results should look like:
Answer1Sum Answer2Sum Answer2Sum
8 7 8
This doesn't work:
from survey in SurveyAnswers
select new
{
Answer1Sum = survey.Sum(),
Answer2Sum = survey.Sum(),
Answer3Sum = survey.Sum()
}
Would this work:
var answer1Sum = SurveyAnswers.Sum( survey => survey.Answer1 );
var answer2Sum = SurveyAnswers.Sum( survey => survey.Answer2 );
var answer3Sum = SurveyAnswers.Sum( survey => survey.Answer3 );
A VB.NET soltuion to this answer for anyone that needs it is as follows:
Dim Answer1Sum = SurveyAnswers.Sum(Function(survey) survey.Answer1)
Dim Answer2Sum = SurveyAnswers.Sum(Function(survey) survey.Answer2)
Dim Answer3Sum = SurveyAnswers.Sum(Function(survey) survey.Answer3)
SurveyAnswers.Sum(r => r.Answer1);