Das Problem ist, dass Sie das Jahr, die Stadt und die QsNo auf dem OutPut
überprüfen Variable nach dem Join ... aber wenn OutPut null ist (was passieren würde, wenn es keine Zeilen in AllCosts gibt), dann sind diese Prüfungen immer falsch, also wird das Paar (Code, OutPut) durch die where-Klausel herausgefiltert. EF erkennt diese Tatsache und generiert eine Abfrage, die effizienter ist, indem nur eine innere Verknüpfung verwendet wird.
Was Sie wirklich tun möchten, ist, Kandidatenzeilen aus Kosten herauszufiltern, anstatt nach (Code-, Kosten-)Paaren zu filtern. Dazu können Sie Ihren Filter nach oben verschieben, sodass er direkt auf die Kostentabelle angewendet wird:
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
};