Count with left outer join in linq to entites - c#

I'm having trouble understanding a left outer join count in Linq to Entities.
My query is:
SELECT Locations.LocationId, Locations.LocationName, LocationPrizes.PrizeId, LocationPrizes.PrizeQuantity, Prizes.PrizeName, ISNULL(COUNT(WonPrizes.WonPrizeId), 0) AS WonPrizes
FROM Locations
INNER JOIN LocationPrizes ON Locations.LocationId = LocationPrizes.LocationId INNER JOIN Prizes ON LocationPrizes.PrizeId = Prizes.PrizeId
LEFT OUTER JOIN WonPrizes ON Locations.LocationId = WonPrizes.LocationId AND Prizes.PrizeId = WonPrizes.PrizeId
GROUP BY Locations.LocationId, Locations.LocationName, LocationPrizes.PrizeId, LocationPrizes.PrizeQuantity, Prizes.PrizeName
My Linq is:
var locationPrizes = from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes = from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
}
};
I can't get the count on teh left outer join part working correctly. Any pointers?

If you happen to have an association from LocationPrizes -> WonPrizes you can just do this:
var locationPrizes =
from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes =
from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
WonPrizes = o.WonPrizes.Count();
}
};
If not, this will work too (works for me with the minor edits below):
var locationPrizes =
from l in context.Locations
select new
{
l.LocationId,
l.LocationName,
Prizes =
from o in l.LocationPrizes
select new
{
o.PrizeId,
o.PrizeQuantity,
o.Prize.PrizeJson
WonPrizes =
(from w in context.WonPrizes
where w.PrizeId == o.PrizeId
&& w.LocationId == l.LocationId
select w)
.Count()
}
};

Related

Converting complex SQL with FULL JOIN to Linq

I am trying to convert a SQL statement to Linq/Entity Framework, and am having a difficult time. Below is the SQL.
SELECT
trust.FName,
trust.MName,
trust.LName
tla.Address,
tma.Address,
at.Descr
FROM CLIENTSSUITS cs
INNER JOIN TRUSTS trust ON trust.SSN = cs.CLIENT
FULL JOIN ADV_TYPES at ON at.CODE = trust.AT
LEFT OUTER JOIN CLIENTADDRESSES tla ON tla.SSN = trust.SSN AND tla.ID = 'L'
LEFT OUTER JOIN CLIENTADDRESSES tma ON tma.SSN = trust.SSN AND tma.ID = 'M'
WHERE cs.PRIMARY = w AND SecondaryRole = x AND cs.ID = y AND cs.Rev = z AND cs.DELETED = 0
GROUP BY trust.FName,
trust.MName,
trust.LName,
tla.Address,
tma.Address,
at.Descr
The FULL JOIN and the GROUP BY seem to be what I'm struggling most with. I've reviewed this SO answer and I understand how to execute a FULL JOIN on its own, but can't figure out how to integrate that into the larger overall query.
TYA for any answers.
Try this
using(var ctx = new Dbcontext())
{
var list = (
from cs in ctx.CLIENTSSUITS
join trust in ctx.TRUSTS on cs.CLIENT equals trust.CLIENT
join at in ctx.ADV_TYPES on at.CODE equals trust.AT into temp from temp.DefaultIfEmpty()
join tla1 in ctx.CLIENTADDRESSES on tla.SSN equals trust.SSN && tla.ID = 'L' into temp2 from subtla1 in temp2.DefaultIfEmpty()
join tla2 in ctx.CLIENTADDRESSES on tla2.SSN equals trust.SSN && tla2.ID = 'M' into temp3 from subtla2 in temp3.DefaultIfEmpty()
where (cs.PRIMARY = w && ?.SecondaryRole = x && cs.ID = y && cs.Rev = z && cs.DELETED = 0)
select new
{
FName = trust.FName,
MName = trust.MName,
LName = trust.LName
LAddress = tla.Address,
MAddress = tma.Address,
Descr = at.Descr
}).ToList();
}
//if the list contains the right result then you can easily group it with this code
var results = list.GroupBy(x => new {
x.FName, x.MName, x.LName, x.LAddress, x.MAddress, Descr
});

SQL to Linq: left join

I need to write linq query. I tried to write example in sql and it works great but I didn't manage to convert it to proper linq
This is my working sql query:
SELECT
pr.descr as product,
prm.Descr
, px.Value AS ParamValue
, prm.Unit AS Unit
, gx.TcPos
FROM [Product] pr
JOIN [PrGroup] prg ON pr.GroupId = prg.Id
LEFT JOIN [PrParamGroup] pg ON ISNULL(pr.PrParamGroupId, prg.PrParamGroupId) = pg.Id
CROSS JOIN [PrParam] prm
LEFT JOIN [PrParam2ProductX] px ON pr.Id = px.ProductId AND prm.Id = px.PrParamId
LEFT JOIN [PrParam2GroupX] gx ON prm.Id = gx.PrParamId AND pg.Id = gx.PrParamGroupId
WHERE
pr.Id = 123 AND
(px.PrParamId IS NOT NULL OR gx.PrParamId IS NOT NULL)
AND (gx.PrParamId <> -1 OR gx.PrParamId IS NULL)
AND (gx.PrParamId IS NOT NULL)
This is my linq attempt:
var productsDesc = (from pr in context.Product.Where(m => m.Id == 123)
join prg in context.PrGroup
on pr.GroupId equals prg.Id
join pg in context.PrParamGroup
on pr.PrParamGroupId equals pg.Id
from prm in context.PrParam
join px in context.PrParam2ProductX
on new { a = pr.Id, b = px.ProductId } equals new { a = prm.Id, b = px.PrParamId }
join gx in context.PrParam2GroupX
on new { prm.Id = gx.PrParamId } equals new { pg.Id = gx.PrParamGroupId }
select new
{
Name = prm.Descr,
Value = px.Value,
Unit = prm.Unit ?? ""
}).ToList();
Your linq dont implement left join and cross join
try this
var productsDesc = (from pr in context.Product.Where(m => m.Id == 123)
join prg in context.PrGroup
on pr.GroupId equals prg.Id
join pg in context.PrParamGroup
on pr.PrParamGroupId equals pg.Id into tmp1
from t1 in tmp1.DefaultIfEmpty()
from prm in context.PrParam
join px in context.PrParam2ProductX
on new { a = pr.Id, b = px.ProductId } equals new { a = prm.Id, b = px.PrParamId } into tmp2
from t2 in tmp2.DefaultIfEmpty()
join gx in context.PrParam2GroupX
on new { prm.Id = gx.PrParamId } equals new { pg.Id = gx.PrParamGroupId } into tmp3
from t3 in tmp3.DefaultIfEmpty()
select new
{
Name = prm.Descr,
Value = t2.Value,
Unit = prm.Unit ?? ""
}).ToList();

How to rewrite sql query to linq

I'm trying to rewrite sql query to linq but can't do it myself.
The most problem for me is to get I,II and III aggregated values.
Sql query:
select o.Name,t.TypeID, SUM(e.I),SUM(e.II),SUM(e.III) from Expenditure e
join Finance f on f.FinanceId = e.FinanceId
join FinanceYear fy on fy.FinanceYearId = f.FinanceYearId and fy.StatusId = 1
join Project p on p.ProjectId = fy.ProjectId
join Organization o on o.OrganizationId = p.OrganizationId
join Type t on t.TypeID = p.TypeID
where fy.Year = 2018
group by o.Name,s.TypeID
and what I have done so far is:
var x = (from e in _db.Expenditures
join f in _db.Finances on e.FinanceId equals f.FinanceId
join fy in _db.FinanceYears on f.FinanceYearId equals fy.FinanceYearId and fy.StatusId = 1 // this does not work, cant join on multiple conditions?
join p in _db.Projects on fy.ProjectId equals p.ProjectId
join o in _db.Organizations on p.OrganizationId equals o.OrganizationId
join s in _db.Types on p.TypeId equals s.TypeId
group new { o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = ?,
II = ?,
III = ?,
}
);
Try something like this:
group new { e, o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = grp.Sum(a => a.e.I),
II = grp.Sum(a => a.e.II),
III = grp.Sum(a => a.e.III),
}
You'll need to adjust the right side of the lambda to navigate to the correct property.
You Need to use the Group by for aggregation methods.
Check the below link for more Knowledge.
How to use aggregate functions in linq with joins?

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

Incorrect values after SQL to LINQ convertion

I need to convert following SQL into LINQ
select
app.id,
app.name,
app.version,
s.application,
s.analysis,
s.behaviour,
(select count(ia.id)
from appInstalled ia
JOIN deviceUser ud ON ia.device_id = ud.device_id
where ia.app_id = app.id) as deviceCount,
max(alrt.alert_date)
from application app
left join score s on app.app_md5 = s.md5hash
left join alert alrt on app.id = alrt.app_id
where app.name like '%gpsnav%'
group by device;
This is what I've done so far
var appQuery = (from app in entities.applications
join score in entities.scores on app.app_md5 equals score.md5hash into appScore
join alrt in entities.alerts on app.id equals alrt.app_id into appAlerts
from s in appScore.DefaultIfEmpty()
from a in appAlerts.DefaultIfEmpty()
let deviceCount = (from iapp in entities.appInstalled
join ud in entities.deviceUser on iapp.device_id equals ud.device_id
where iapp.id == app.id
select iapp.id).Count()
where string.IsNullOrEmpty(searchTerm) || app.name.ToLower().Contains(searchTerm.ToLower())
select new
{
AppId = app.id,
AppName = app.name,
AppVersion = app.version,
AppScore = s.application,
Analysis = s.analysis,
Behavior = s.behaviour,
Devices = deviceCount,
AlertDate = a.alert_date
});
var grouped = from a in appQuery
group a by new
{
a.AppId,
a.AppName,
a.AppVersion,
a.AppScore,
a.Analysis,
a.Behavior,
a.Devices,
a.AlertDate
} into g
select new
{
g.Key.AppId,
g.Key.AppName,
g.Key.AppVersion,
g.Key.AppScore,
g.Key.Analysis,
g.Key.Behavior,
g.Key.Devices,
AlertDate = g.Max(x=>x.AlertDate)
};
The above LINQ works but the data is incorrect for Device and AlertDate. What I am missing in here? Also I am not getting max of AlertDate while grouping in LINQ.

Categories