SUM and COUNT in single LINQ to SQL query - c#

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.

Related

Slow LINQ query because of Where+ToDictionary

I have this query that I need to run:
IEnumerable<MerchantWithParameters> merchants =
from i in (
from m in d.GetTable<Merchant>()
join mtp in d.GetTable<MerchantToParameters>() on m.Id equals mtp.MerchantId into mtps
from mtp in mtps.DefaultIfEmpty()
join cp in d.GetTable<ContextParameters>() on mtp.ContextParametersId equals cp.Id into cps
from cp in cps.DefaultIfEmpty()
select new {Merchant = m, ContextParameter = cp}
)
group i by new { i.Merchant.Id } into ig
select new MerchantWithParameters()
{
Id = ig.Key.Id,
Parameters = ig.Where(g => g.ContextParameter != null).ToDictionary(g => g.ContextParameter.Key, g => g.ContextParameter.Text)
};
For some reason it takes really long time for this query to be completed.
I believe that it has something to do with
Parameters = ig.Where(g => g.ContextParameter != null).ToDictionary(g => g.ContextParameter.Key, g => g.ContextParameter.Text)
Because when I remove this line, query starts to execute really fast.
Could you please show me what am I doing wrong?
UPDATE:
I am using ToList() to extract data from the database.
It is known SQL limitation. You cannot get grouped items, only grouping key or aggregation result. Since you need all records, we can do grouping on the client side, but previously maximally limit retrieved data.
var query =
from m in d.GetTable<Merchant>()
from mtp in d.GetTable<MerchantToParameters>().LeftJoin(mtp => m.Id == mtp.MerchantId)
from cp in d.GetTable<ContextParameters>().LeftJoin(cp => mtp.ContextParametersId == cp.Id)
select new
{
MerchantId = m.Id,
ContextParameterKey = (int?)cp.Key,
ContextParameterText = cp.Text
};
var result =
from q in query.AsEnumerable()
group q by q.MerchantId into g
select new MerchantWithParameters
{
Id = g.Key,
Parameters = g.Where(g => g.ContextParameterKey != null)
.ToDictionary(g => g.ContextParameterKey.Value, g => g.ContextParameterText)
};
var merchants = result.ToList();

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

Transform SQL Query to LINQ

I would like if someone helps me to convert this SQL Query to LINQ syntax.
SELECT i.Id, i.Condomino as Condomino, i.Interno as Interno,
p.NomePiano as NomePiano, s.Nome as NomeCondominio,
m.millesimi_fabbisogno_acs, m.millesimi_fabbisogno_riscaldamento
FROM Interni i
INNER JOIN Piani p ON i.IdPiano = p.Id
INNER JOIN Stabili s ON i.IdStabile = s.Id
LEFT JOIN MillesimiTabellaC m ON i.Id = m.idInterno
WHERE s.IdCondominio = {0}
I tried using something like this, but is not working..
return _Db.Interni.Include("Piani").Where(x => x.Piani.IdCondominio == iidcond).ToList();
I made it on-the-spot (so it's not tested), but perhaps it's enough to give you the idea. I'm also assuming that your DB model has foreign keys set up.
var result = _db.Interni
.Where(i => i.Stabili.IdCondominio = [value])
.Select(i => new
{
i.Id,
Condomino = i.Condomino,
Interno = i.Interno,
NomePiano = i.Piani.NomePiano,
NomeCondominio = i.Stabili.Nome,
i.MillesimiTabellaC.millesimi_fabbisogno_acs,
i.MillesimiTabellaC.millesimi_fabbisogno_riscaldamento
})
.ToList();
update
In case you don't have a foreign key between Interni and MillesimiTabellaC, try this:
var result = _db.Interni
.Include(i => i.Piani)
.Include(i => i.Stabili)
.Where(i => i.Stabili.IdCondominio = [value])
.Select(i => new
{
Interni = i,
MillesimiTabellaC = _db.MillesimiTabellaC.Where(m => i.Id = m.idInterno)
})
.Select(x => new
{
Id = x.Interni.Id,
Condomino = x.Interni.Condomino,
Interno = x.Interni.Interno,
NomePiano = x.Interni.Piani.NomePiano,
NomeCondominio = x.Interni.Stabili.Nome,
x.MillesimiTabellaC?.millesimi_fabbisogno_acs,
x.MillesimiTabellaC?.millesimi_fabbisogno_riscaldamento
})
.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);

Need help for a more beautiful LINQ to SQL query

Following is a T_SQL query for AdventureWorks database:
SELECT Name
FROM Production.Product
WHERE ListPrice >= ANY
(SELECT MAX (ListPrice)
FROM Production.Product
GROUP BY ProductSubcategoryID)
I try writing a LINQ query for this:
var groupMaxPricesquery2 = from product in dc.Products
group product by product.ProductSubcategoryID into productGroup
select productGroup.Max(eachProductInGroup => eachProductInGroup.ListPrice);
var query = from product in dc.Products
where groupMaxPricesquery2.Any(listPrice => listPrice <= product.ListPrice)
select product.Name;
How can I make it more beautiful (i.e. combining those queries together, or a more efficient approach)?
Thank you very much
Give either of these a try:
var query = from product in dc.Products
let groupMaxPricesQuery = dc.Products.GroupBy(p => p.ProductSubcategoryID)
.Select(g => g.Max(item => item.ListPrice))
where groupMaxPricesQuery.Any(listPrice => listPrice <= product.ListPrice)
select product.Name;
// or
var query = dc.Products
.Select(product => new {
Product = product,
GroupedMaxPrices = dc.Products.GroupBy(p => p.ProductSubcategoryID)
.Select(g => g.Max(item => item.ListPrice))
})
.Where(item => item.GroupedMaxPrices.Any(listPrice => listPrice <= item.Product.ListPrice))
.Select(item => item.Product.Name);
Maybe I'm missing something with the grouping, but I don't see why it is necessary.
var maxListPrice = dc.Products.Max(p => p.ListPrice);
var query = dc.Products.Where(p => p.ListPrice >= maxListPrice).Select(n => n.Name);

Categories