Problemet er, at du tjekker År, By og QsNo på OutPut
variabel efter joinforbindelsen... men hvis OutPut er null (hvilket ville ske, hvis der ikke er rækker i AllCosts), så vil disse kontroller altid være falske, så parret (kode, OutPut) vil blive filtreret ud af where-klausulen. EF registrerer dette faktum og genererer en forespørgsel, som er mere effektiv ved blot at bruge en indre joinforbindelse.
Det, du virkelig vil gøre, er at filtrere kandidatrækker fra omkostninger, i stedet for at filtrere på (kode, omkostninger) par. For at gøre dette kan du flytte dit filter op, så det gælder direkte for tabellen Omkostninger:
var Result = from code in ent.ProductCodes
join cost
in ent.Costs.Where(c => c.Year == Year && c.City == City && c.QsNo == Qsno)
on new { code.Year, code.Code } equals new { cost.Year, cost.Code }
into AllCosts
from OutPut in AllCosts.DefaultIfEmpty()
where code.PageNo == PageNo
select new
{
ProductCode = code.Code
Col6 = OutPut.Price
};