Problemet är att du kontrollerar år, stad och QsNo på OutPut
variabel efter join... men om OutPut är null (vilket skulle hända om det inte finns några rader i AllCosts) så kommer dessa kontroller alltid att vara falska, så paret (kod, OutPut) kommer att filtreras bort av where-satsen. EF upptäcker detta faktum och genererar en fråga som är mer effektiv genom att bara använda en inre koppling.
Vad du verkligen vill göra är att filtrera bort kandidatrader från kostnader, snarare än att filtrera på (kod, kostnad) par. För att göra detta kan du flytta ditt filter uppåt, så att det gäller direkt i kostnadstabellen:
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
};