Linq Dynamic Query With Group By - c#

I need extra where clause for my Linq query. For example if customer choose a date filter so i need to date filter to my query etc... When i try to myQuery.Where predicate there is visible just group by's field.
How can i append new where condition to my query.
//for example i need dynamically append o.OrderDate==Datetime.Now or another where clause
var myQuery =(from o in _db.Orders
join l in _db.OrderLines.Where(x => x.ParaBirimi == model.ParaBirimi) on o.orderId equals
l.OrderId
where o.OrderDate.Value.Year == year1
group o by new {o.OrderDate.Value.Month}
into g
select
new
{
Month = g.Key.Month,
Total = g.Select(t => t.OrderLines.Sum(s => s.OrderTotal)).FirstOrDefault()
});

You are too late at the end of the query to add new Where. You have already grouped the data, and projected it, removing nearly all the fields.
Try:
var baseQuery = from o in _db.Orders
join l in _db.OrderLines.Where(x => x.ParaBirimi == model.ParaBirimi) on o.orderId equals l.OrderId
where o.OrderDate.Value.Year == year1
select new { Order = o, OrderLine = l };
if (something)
{
baseQuery = baseQuery.Where(x => x.Order.Foo == "Bar");
}
var myQuery = (from o in baseQuery
group o by new { o.Order.OrderDate.Value.Month }
into g
select
new
{
Month = g.Key.Month,
Total = g.Sum(t => t.OrderLine.OrderTotal)
});
Clearly you can have multiple if. Each .Where() is in && (AND) with the other conditions.
Note how the result of the join is projected in an anonymous class that has two properties: Order and OrderLine

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 get Count of IGrouping<'a, Foo> Linq

I am attempting to write a query that returns a list grouped by OrderID and DateTime value. My first query returns a grouped count which is of type:
IGrouping<'a, Foo> SomeList
Now I am attempting to execute a loop to produce a view model of type List<ViewModel> model based on the above. The problem is an Order may contain more than 1 item OrderLines, I wanted to add a check if the count is > 1 then loop through the sub items and create an object to add to the List object.
var query = (from o in db.Orders
join ol in db.OrderLines on o.OrderID equals ol.OrderID
join u in db.Users on o.UserSalesID equals u.UserID
join r in db.Reports on o.UserSalesID equals r.UserId
where o.Timestamp <= timeNow && o.Timestamp >= timeYesterday && u.UserID == o.UserSalesID
group ol by new { o.Timestamp, o.OrderID } into g
select g).ToList();
// the loop
foreach (var orderLineList in query)
{
foreach (var item in orderLineList) // how to get a count of OrderLineList here
{
// check if count is more than 1 then create an annon object and get total price of order etc
// if not then carry on as normal
model.Add(new ReportViewModel()
{
Gross = orderLineList.Sum(ol => ol.RetailPrice),
Net = orderLineList.Sum(ol => ol.RetailPrice), // minus expense,
PaymentType = orders.Where(o => o.OrderID == item.OrderID).FirstOrDefault().PaymentID,
Quantity = db.OrderLines.Where(ol => ol.OrderID == item.OrderID).Sum(ol => ol.Quantity),
OrderID = item.OrderID
});
}
}

Sum(with Coalesce) with Group By in linq (for EF6)

I have the following SQL that I would like to write as a single linq statement:
SELECT
P.PartyId,
P.PartyDate,
SUM(COALESCE(R.PaidAmount, 0)) AS AmountPaid
FROM
Party AS P
LEFT JOIN Reservation as R
ON P.PartyID = R.PartyID
GROUP BY P.PartyID, P.PartyDate
ORDER BY P.PartyDate DESC
The best I can do is use two sets of linq queries, like so:
var localList = from partyList in localDb.Parties
join reservationList in localDb.Reservations on
partyList.PartyID equals reservationList.PartyID into comboList
from newList in comboList.DefaultIfEmpty()
select new PartyAmounts {
PartyID = partyList.PartyID,
PartyDate = partyList.PartyDate,
AmountPaid = (newList.PaidAmount ?? 0) };
var secondList = from groupList in localList
group groupList by new {
groupList.PartyID,
groupList.PartyDate} into resList
select new PartyAmounts {
PartyID = resList.Key.PartyID,
PartyDate=resList.Key.PartyDate,
AmountPaid = resList.Sum(x => x.AmountPaid)};
I don't care if it's a method chain or a lambda but I would love to know how this is supposed to go together. I can only barely understand the two I've got now.
Thanks for the help.
var list = from partyList in localDb.Parties
join reservationList in localDb.Reservations on partyList.PartyID equals reservationList.PartyID into comboList
from details in comboList.DefaultIfEmpty() // Left join
group details by new {partyList.PartyID, partyList.PartyDate} into grouped // So that the group have both keys and all items in details
select new PartyAmounts
{
PartyID = grouped.Key.PartyID,
PartyDate = grouped.Key.PartyDate,
AmountPaid = grouped.Sum(x => x.AmountPaid ?? 0)}
};

LINQ - multi join with Group by and get average

I'm trying to write this select in LINQ but Im not successful to fix it for long time. I also tried LINQ - join with Group By and get average but it doesn't work in my code. It is obviously that I'm wrong.
SQL:
SELECT name_type, AVG(t.price) as avgPrice FROM type tp
JOIN location l ON l.ID_type = tp.ID
JOIN event e ON e.ID_location = l.ID
JOIN ticket t ON t.ID_event = e.ID
GROUP BY tp.name_type
LINQ:
var q3 = from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals u.ID_location
join t in db.ticket on e.ID equals t.ID_event
group tp by new {Type_name = tp.type_name} into grp
select new
{
Type_name = grp.Key.type_name,
avgPrice = grp.Average( x => x.ticket.price)
};
There are a few problems:
There is an error in the second join—I believe u.ID_location needs to be e.ID_location.
I think you are grouping on the wrong entity, try grouping by t instead of tp.
You don't need the anonymous type in the group by.
Try this:
var results =
from l in db.location
join tp in db.type on l.ID_type equals tp.ID
join e in db.event on l.ID equals e.ID_location
join t in db.ticket on e.ID equals t.ID_event
group t by new tp.type_name into grp
select new
{
Type_name = grp.Key,
avgPrice = grp.Average(x => x.price)
};
If you happen to have navigation properties set up between your entities, this would be a lot easier. It's pretty hard to tell how the entities are supposed to be related, but I'm thinking something like this would work:
// average ticket price per location type
var results =
from t in db.ticket
group t by t.event.location.type.type_name into g
select new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
};
Or in fluent syntax:
var results = db.ticket.GroupBy(t => t.event.location.type.type_name)
.Select(g => new
{
Type_name = g.Key,
avgPrice = g.Average(x => x.price)
});

transform sql to linq with join, group-by and where

I have the following sql, which I want to convert to linq
SELECT Contrato.finca, SUM(Pago.Importe_subtotal)
FROM Pago, Contrato
WHERE Pago.Contrato = Contrato.ID AND Pago.pagado = 1
GROUP BY Contrato.finca
ORDER BY 2 DESC
GO
What I have now in linq is the following, but the group by doesn't work.
var x = from contrato in ctx.Contratos
join pago in ctx.Pagos
on contrato.ID equals pago.Contrato
where pago.pagado == true
group contrato by contrato.finca
select contrato.Finca1;
Think this should work:
ctx.Pagos.Where(m=>m.pagado==true).GroupBy(m=>m.Contrato.finca)
.Select(m=> new { Id= m.Key, Val= m.Sum(n => n.Importe_subtotal)})
Try
var x = from contrato in ctx.Contratos
join pago in ctx.Pagos
on contrato.ID equals pago.Contrato
where pago.pagado == true
group new {contrato, pago} by contrato.finca into g
select new {
key = g.Key,
sum = g.Sum(p => p.pago.Importe_subtotal)
};

Categories