How to generate duplicate items in a list using LINQ? - c#

this is LINQ query I have used
var result = (from price in inventoryDb.Pricing.AsNoTracking()
where price.Quantity > 0m
select new
{
TagNo = price.TagNo,
SellingRate = price.SellingRate,
Quantity = price.Quantity
}).ToList();
Based on the Quantity value I need to generate duplicate items in the list.
Output :
result = [0]{TagNo="100", SellingRate=1500.00, Quantity=1}
[1]{TagNo="101", SellingRate=1600.00, Quantity=2}
Expected Result:
result = [0]{TagNo="100", SellingRate=1500.00}
[1]{TagNo="101", SellingRate=1600.00}
[2]{TagNo="101", SellingRate=1600.00}

You can use Enumerable.SelectMany + Enumerable.Range:
var result = inventoryDb.Pricing.AsNoTracking()
.Where(p => p.Quantity > 0m)
.SelectMany(p => Enumerable.Range(0, p.Quantity)
.Select(i => new
{
TagNo = p.TagNo,
SellingRate = p.SellingRate
}))
.ToList();
If that's not supported by your LINQ provider (f.e. Linq-To-Entities), the easiest is to use Linq-To-Objects. To avoid that all is loaded into memory you should use AsEnumerable after the Where:
var result = inventoryDb.Pricing.AsNoTracking()
.Where(p => p.Quantity > 0m)
.AsEnumerable()
.SelectMany(p => Enumerable.Range(0, p.Quantity)
.Select(i => new
{
TagNo = p.TagNo,
SellingRate = p.SellingRate
}))
.ToList();

Keeping with the query syntax just add a Enumerable.Repeat as follows:
var result = (from price in inventoryDb.Pricing.AsNoTracking()
where price.Quantity > 0m
from dup in Enumerable.Repeat(0,price.Quantity)
select new
{
TagNo = price.TagNo,
SellingRate = price.SellingRate,
}).ToList();
If indeed linq to entities does not support then add AsEnumerable like follows:
var result = (from price in inventoryDb.Pricing.AsNoTracking()
.Where(p => p.Quantity > 0m)
.AsEnumerable() //Loads only the filtered items to memory
from dup in Enumerable.Repeat(0,price.Quantity)
select new
{
TagNo = price.TagNo,
SellingRate = price.SellingRate,
}).ToList();
You can also use Enumerable.Range but because you do not use the value of that collection (and in my opinion also just that it describes better what you are doing) I decided just to go with Repeat

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);

C# Linq -Extension Method

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() });

Categories