Sum(with Coalesce) with Group By in linq (for EF6) - c#

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

Related

linq left join with filtering in joined

I am getting duplication meals here
IEnumerable<DTOHotMealsPrice> lst = (from m in this.dbEntity.HOT_MEALS
join ml in this.dbEntity.HOT_MEALS_PRICE on m.MEALSID equals ml.MEALSID into mls
from mls1 in mls.DefaultIfEmpty()
where mls1.HOTID==hotelId
select new DTOHotMealsPrice
{
MEALSID = m.MEALSID,
MEALSNAME = m.MEALSNAME,
CHPRICE = mls1.CHPRICE,
PRICE = mls1.PRICE,
HOTID = mls1.HOTID
}).Distinct().ToList();
I want to list all HOT_MEALS and also join with
HOT_MEALS_PRICE when a mealsid reference on it
When mls1.HOTID==hotelId, this will getting innerjoin results
How could it will a proper result
Two Way solve Solution
Remove Where Case
Add where Case In Join table
Show for Where Case Blow Linq Query
first Query
IEnumerable<DTOHotMealsPrice> lst = (from m in this.dbEntity.HOT_MEALS
join ml in this.dbEntity.HOT_MEALS_PRICE.where(c=>c.HOTID==hotelId) on m.MEALSID equals ml.MEALSID into mls
from mls1 in mls.DefaultIfEmpty()
select new DTOHotMealsPrice
{
MEALSID = m.MEALSID,
MEALSNAME = m.MEALSNAME,
CHPRICE = mls1.CHPRICE,
PRICE = mls1.PRICE,
HOTID = mls1.HOTID
}).Distinct().ToList();
Second is:
IEnumerable<DTOHotMealsPrice> lst = (from m in this.dbEntity.HOT_MEALS
join ml in this.dbEntity.HOT_MEALS_PRICE on m.MEALSID equals ml.MEALSID into mls
from mls1 in mls.where(c=>c.HOTID==hotelId).DefaultIfEmpty()
select new DTOHotMealsPrice
{
MEALSID = m.MEALSID,
MEALSNAME = m.MEALSNAME,
CHPRICE = mls1.CHPRICE,
PRICE = mls1.PRICE,
HOTID = mls1.HOTID
}).Distinct().ToList();

How to include all fields in a multiple join into Linq statement?

var largeset =
from invs in context.Invoices
join lines in context.InvoiceLines on invs.InvoiceId equals lines.InvoiceId
join tracks in context.Tracks on lines.TrackId equals tracks.TrackId into grp
select new
{
Invoice = invs,
Detail = grp
};
In the above join into statement, Detail is a list but it only contains Invoice and Track columns. I want to be able to get columns from InvoiceLine as well.
Thanks in advance.
If you want to get the line info list for the invoice, you need to move the into to the first join and perform the other join inside the outer select.
Something like this:
var largeset =
from inv in context.Invoices
join line in context.InvoiceLines on inv.InvoiceId equals line.InvoiceId into lines
select new
{
Invoice = inv,
Lines =
from line in lines
join track in context.Tracks on line.TrackId equals track.TrackId
select new { Line = line, Track = track }
};
As an alternative to Ivan's solution which should yield better performance.
var largeset =
from invs in context.Invoices
join lines in context.InvoiceLines on invs.InvoiceId equals lines.InvoiceId
join tracks in context.Tracks on lines.TrackId equals tracks.TrackId
group new { invs, lines, tracks }
by new
{
invs.InvoiceId,
invs.InvoiceDate,
invs.CustomerId,
invs.Customer.LastName,
invs.Customer.FirstName
} into grp
select new
{
InvoiceId = grp.Key.InvoiceId,
InvoiceDate = grp.Key.InvoiceDate,
CustomerId = grp.Key.CustomerId,
CustomerLastName = grp.Key.LastName,
CustomerFirstName = grp.Key.FirstName,
CustomerFullName = grp.Key.LastName + ", " + grp.Key.FirstName,
TotalQty = grp.Sum(l => l.lines.Quantity),
TotalPrice = grp.Sum(l => l.lines.UnitPrice),
Tracks = grp.Select(t => t.tracks)
};

Linq Dynamic Query With Group By

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

linq to sql distinct values or group by

I have the folowing linq query.
How can I modify the query to return distinct values for CityFoo property only?
var query = from f in db.Foos
join b in db.Bars on f.IDFoo equals b.IDFoo
join fb in db.Fubars on b.IDBar equals fb.IDBar
select new MyViewModel {
IDFoo = f.IDFoo,
NameFoo = f.NameFoo,
CityFoo = f.CityFoo,
NameBar = b.NameBar,
NameFubar = fb.NameFubar };
I think you are missing information on your query.
If you want the first value to be used on the other properties, you need to tell that to Linq
So I am guessing that you actually want to group and then take the first.
Or...something like this:
var query = from f in db.Foos
join b in db.Bars on f.IDFoo equals b.IDFoo
join fb in db.Fubars on b.IDBar equals fb.IDBar
group new { f, b, fb } by f.CityFoo into grp
let first = grp.FirstOrDefault()
select new MyViewModel {
IDFoo = first.f.IDFoo,
NameFoo = first.f.NameFoo,
CityFoo = grp.Key,
NameBar = first.b.NameBar,
NameFubar = first.fb.NameFubar };

SQL to Linq select multiple columns in group by

I would like to convert a SQL statement to LINQ but i have some problems doing it.
The sql statement is :
SELECT
C.[Call_Date], CC.[Company], R.Resolution,
COUNT_BIG(*) AS CNT,
SUM([Duration]) AS Total
FROM
[Calls] C
Join
[CompanyCharges] CC on [Company_Charge] = [CompanyCharge]
Join
[Resolutions] R on C.Call_Resolution = R.Resolution
where
Call_Date >= '05/29/2013'
Group By
C.[Call_Date], CC.[Company], CC.[CompanyCharge], R.Resolution, R.Resolution_Order
I wrote something like :
var stats = from c in dbContext.Calls
join cc in dbContext.CompanyCharges on c.Company_Charge equals cc.CompanyCharge
join r in dbContext.Resolutions on c.Call_Resolution equals r.Resolution
where (c.Call_Date > "05/29/2013")
group new { c, cc, r } by new { c.Call_Date, cc.CompanyCharge, r.Resolution, r.Resolution_Order } into statsGroup
select new { Count = statsGroup.Count(), ??? };
I managed to count the elements, but i need a sum[duration] and some columns from different tables.
Please share your wisdome with me.
Assuming that the [Duration] field is part of the [Calls] table:
var stats = /* ... */
select new
{
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};
You'd probably want to include your grouping fields in the new anonymous type as well:
var stats = /* ... */
select new
{
Call_Date = statsGroup.Key.c.Call_Date,
CompanyCharge = statsGroup.Key.cc.CompanyCharge,
Resolution = statsGroup.Key.r.Resolution,
Count = statsGroup.Count(),
Total = statsGroup.Sum(stat => stat.c.Duration),
};

Categories