C# Linq -Extension Method - c#

How to use extension methods to form the second query as the first one.
1) var query = from cm in cust
group cm by cm.Customer into cmr
select (new { CKey = cmr.Key, Count = cmr.Count() });
(second query is not well formed)
2) var qry = cust.GroupBy(p => p.Customer).
Select(new { CKey = p.Key, Count = p.Count });

Try this:
var query = cust.GroupBy(p => p.Customer)
.Select(g => new { CKey = g.Key, Count = g.Count() });
You can also simplify this into a single call to this GroupBy overload though:
var query = cust.GroupBy(p => p.Customer,
(key, g) => new { CKey = key, Count = g.Count() });
Note that I've changed the name of the lambda expression's parameter name for the second line to g - I believe that gives more of a clue that you're really looking at a group rather than a single entity.
I've also moved the dot onto the second line in the form that still uses Select - I find this makes the query easier to read; I usually line up the dots, e.g.
var query = foo.Where(...)
.OrderBy(...)
.GroupBy(...)
.Select(...)

I think you need:
var qry = cust.GroupBy(p => p.Customer)
.Select(grp => new { CKey = grp.Key, Count = grp.Count() });

Related

How to shorten the LINQ query to calculate the sum for parent table from child tables

Currently I have this LINQ query which calculate the totalcount of a parent table (CafeTables) from child tables (CafeTableDetails). These code works. But somehow, I believe these code can the shorten.
var selectedTable = db.CafeTables.Where(c => c.TableNo.Equals(userName)).SingleOrDefault();
var selectedTableDetailsRaw = db.CafeTableDetails.
Where(cd => cd.CafeTableId == selectedTable.Id);
selectedTable.TotalOrders = selectedTableDetailsRaw.Count();
I think you can try to use linq JOIN and GroupBy to make it.
var result = db.CafeTables.Where(c => c.TableNo == userName)
.Join(db.CafeTableDetails.GroupBy(x=>x.CafeTableId)
.Select(g => new { CafeTableId = g.Key, cnt = g.Count() }),
st => st.Id,
cd => cd.CafeTableId,
(st,cd) => new
{
st.Id,
cd.cnt
//..... your expect property
});

SUM and COUNT in single LINQ to SQL query

I'm trying to create the following query in LINQ-TO-SQL.
select count(*), sum( o.CostInCents ) from Orders o
where Flag = true;
I came up with the following LINQ query:
var q = db.Orders
.Where(o => o.Flag )
var result = q
.GroupBy(o => 1)
.Select(g => new MyDTO
{
NoOfOrders = g.Count(),
TotalInCents = g.Sum(o => o.CostInCents )
})
.SingleOrDefaultAsync();
Is there a better way?
Is .GroupBy(o => 1) even OK?
The other option would be to do two queries, like below.
var q = db.Orders
.Where(o => o.Flag );
//No groupBy
var result2 = new MyDTO
{
NoOfCostedOrders = q.Count(),//hit the db
TotalInCents = q.Sum(o => o.CostInCents )//hit the db 2nd time
};
How should I judge which approach is better?
Thanks in advance!
This query can be rewritten in sql format as follows
var orderList = db.Orders.Where(o => o.Flag );
var orderSummary = from o in orderList
group o by 1 into p
select new
{
Items = p.Count(),
Total = p.Sum( x => x.CostInCents)
}
I think what you are searching for is the following slight adjustment:
var q = db.Orders
.Where(o => o.Flag).Select(o => o.CostInCents).ToList(); // hit the db here once
//No groupBy
var result2 = new MyDTO
{
NoOfCostedOrders = q.Count(), // don't hit the db
TotalInCents = q.Sum() // don't hit the db a 2nd time
};
If you have a question to my adjustment feel free to comment.

Cannot Group By on multiple columns and Count

I want to write this simple query with Linq:
select issuercode,securitycode,dataprocessingflag,COUNT(issuercode) as cnt
from cmr_invhdr
where ProcessedLike <> 'STMNT ONLY'
group by issuercode,securitycode,dataprocessingflag
order by Issuercode
I've tried the following code but I get this error( DbExpressionBinding requires an input expression with a collection ResultType.
Parameter name: input) :
var lstCMRInvHdrNips = (from r in e.CMR_INVHDR
where r.ProcessedLike != "STMNT ONLY"
select new {
r.IssuerCode,
r.SecurityCode,
CountofIssuerCode = r.IssuerCode.Count(),
r.DataProcessingFlag
}
).GroupBy(x =>
new {
x.IssuerCode,
x.SecurityCode,
x.DataProcessingFlag,
x.CountofIssuerCode
}
).OrderBy(x => x.Key.IssuerCode).ToList();
Is there any sense to count issuercode while grouping by this field at once? As when groupped by a field, it's COUNT will always be 1.
Probably you should not group by issuercode and count it after the GroupBy in a separate Select statement:
var result = e.CMR_INVHDR
.Where(r => r.ProcessedLike != "STMNT ONLY")
.GroupBy(r => new { r.SecurityCode, r.DataProcessingFlag })
.Select(r => new
{
Value = r.Key,
IssuerCodesCount = r.GroupBy(g => g.IssuerCode).Count()
})
.ToList();

Group By using Select statement in Linq

var query = from i in SFC.Supplies_ReceiveTrans
orderby i.Poprctnm descending
select new { RR = i.Poprctnm };
Result:
RR-01,
RR-01,
RR-02,
RR-02,
RR-02,
RR-TEST,
RR-TEST,
How do i group RR in this kind of statement
Result:
RR-01,
RR-02,
RR-TEST
just a few modification to ask if is it possible to do this one or what you have in your mind? Sorry for asking too much just really interested in learning more on linq.. how do i convert it into string coz its showing true or false.. boolean statement
var query = SFC.Supplies_ReceiveTrans.Select(s =>
s.Poprctnm.StartsWith(p))
.Distinct()
.OrderBy(p => p)
.Select(p => new { RR = p })
.Take(10);
You can use Distinct or GroupBy methods in this case
var query = SFC.Supplies_ReceiveTrans.Select(s=> s.Poprctnm)
.Distinct()
.OrderByDescending(p => p)
.Select(p=> new { RR = p });
if you use OrderByDescending then the result will be
RR-TEST
RR-02
RR-01
But I think you want OrderBy then the result will be
RR-01
RR-02
RR-TEST
So try below
var query = SFC.Supplies_ReceiveTrans.Select(s=> s.Poprctnm)
.Distinct()
.OrderBy(p => p)
.Select(p=> new { RR = p });
var query = SFC.Supplies_ReceiveTrans
.GroupBy(x=>x.Poprctnm)
.Select(g=>g.First())
.OrderByDescending(x=>x.Poprctnm)
.Select(x=>new { RR = x.Poprctnm });
If you want to get result as group:
var query = SFC.Supplies_ReceiveTrans
.GroupBy(x=>x.Poprctnm)
.OrderByDescending(g=>g.Key);
var result = SFC.Supplies_ReceiveTrans
.Select(x => new { RR = x.Poprctnm })
.Distinct()
.OrderByDescending(x => x.Poprctnm);
Looks like you need Distinct here, not group
var query = SFC.Supplies_ReceiveTrans
.Select(x => new {RR = i.Poprctnm})
.Distinct()
.OrderByDescending(i => i);

Group By Multiple Columns

How can I do GroupBy multiple columns in LINQ
Something similar to this in SQL:
SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>
How can I convert this to LINQ:
QuantityBreakdown
(
MaterialID int,
ProductID int,
Quantity float
)
INSERT INTO #QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM #Transactions
GROUP BY MaterialID, ProductID
Use an anonymous type.
Eg
group x by new { x.Column1, x.Column2 }
Procedural sample:
.GroupBy(x => new { x.Column1, x.Column2 })
Ok got this as:
var query = (from t in Transactions
group t by new {t.MaterialID, t.ProductID}
into grp
select new
{
grp.Key.MaterialID,
grp.Key.ProductID,
Quantity = grp.Sum(t => t.Quantity)
}).ToList();
For Group By Multiple Columns, Try this instead...
GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new
{
Key1 = key.Column1,
Key2 = key.Column2,
Result = group.ToList()
});
Same way you can add Column3, Column4 etc.
Since C# 7 you can also use value tuples:
group x by (x.Column1, x.Column2)
or
.GroupBy(x => (x.Column1, x.Column2))
C# 7.1 or greater using Tuples and Inferred tuple element names (currently it works only with linq to objects and it is not supported when expression trees are required e.g. someIQueryable.GroupBy(...). Github issue):
// declarative query syntax
var result =
from x in inMemoryTable
group x by (x.Column1, x.Column2) into g
select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));
// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
.Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));
C# 3 or greater using anonymous types:
// declarative query syntax
var result3 =
from x in table
group x by new { x.Column1, x.Column2 } into g
select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };
// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
.Select(g =>
new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });
You can also use a Tuple<> for a strongly-typed grouping.
from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
LastName = grouping.Key.Item1,
FirstName = grouping.Key.Item2,
MiddleName = grouping.Key.Item3,
DayCount = grouping.Count(),
AmountBilled = grouping.Sum(x => x.Rate),
}
Though this question is asking about group by class properties, if you want to group by multiple columns against a ADO object (like a DataTable), you have to assign your "new" items to variables:
EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
.Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
var Dups = ClientProfiles.AsParallel()
.GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
.Where(z => z.Count() > 1)
.Select(z => z);
var Results= query.GroupBy(f => new { /* add members here */ });
A thing to note is that you need to send in an object for Lambda expressions and can't use an instance for a class.
Example:
public class Key
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
This will compile but will generate one key per cycle.
var groupedCycles = cycles.GroupBy(x => new Key
{
Prop1 = x.Column1,
Prop2 = x.Column2
})
If you wan't to name the key properties and then retreive them you can do it like this instead. This will GroupBy correctly and give you the key properties.
var groupedCycles = cycles.GroupBy(x => new
{
Prop1 = x.Column1,
Prop2= x.Column2
})
foreach (var groupedCycle in groupedCycles)
{
var key = new Key();
key.Prop1 = groupedCycle.Key.Prop1;
key.Prop2 = groupedCycle.Key.Prop2;
}
group x by new { x.Col, x.Col}
.GroupBy(x => (x.MaterialID, x.ProductID))
.GroupBy(x => x.Column1 + " " + x.Column2)
For VB and anonymous/lambda:
query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })

Categories