J'ai le SQL suivant, que j'essaye de traduire en LINQ:
SELECT f.value
FROM period as p
LEFT OUTER JOIN facts AS f ON p.id = f.periodid AND f.otherid = 17
WHERE p.companyid = 100
J'ai vu l'implémentation typique de la jointure externe gauche (c'est-à-dire into x from y in x.DefaultIfEmpty()
etc.), mais je ne sais pas comment introduire l'autre condition de jointure (AND f.otherid = 17
)
EDIT
Pourquoi la condition AND f.otherid = 17
Fait-elle partie de JOIN, et non de la clause WHERE? Parce que f
peut ne pas exister pour certaines lignes et je veux toujours que ces lignes soient incluses. Si la condition est appliquée dans la clause WHERE, après la commande JOIN, le comportement que je souhaite ne me convient pas.
Malheureusement ceci:
from p in context.Periods
join f in context.Facts on p.id equals f.periodid into fg
from fgi in fg.DefaultIfEmpty()
where p.companyid == 100 && fgi.otherid == 17
select f.value
semble être équivalent à ceci:
SELECT f.value
FROM period as p
LEFT OUTER JOIN facts AS f ON p.id = f.periodid
WHERE p.companyid = 100 AND f.otherid = 17
ce qui n'est pas tout à fait ce que je recherche.
Vous devez introduire votre condition de jointure avant d'appeler DefaultIfEmpty()
. Je voudrais juste utiliser la syntaxe de la méthode d'extension:
from p in context.Periods
join f in context.Facts on p.id equals f.periodid into fg
from fgi in fg.Where(f => f.otherid == 17).DefaultIfEmpty()
where p.companyid == 100
select f.value
Ou vous pouvez utiliser une sous-requête:
from p in context.Periods
join f in context.Facts on p.id equals f.periodid into fg
from fgi in (from f in fg
where f.otherid == 17
select f).DefaultIfEmpty()
where p.companyid == 100
select f.value
cela fonctionne aussi, ... si vous avez plusieurs jointures de colonne
from p in context.Periods
join f in context.Facts
on new {
id = p.periodid,
p.otherid
} equals new {
f.id,
f.otherid
} into fg
from fgi in fg.DefaultIfEmpty()
where p.companyid == 100
select f.value
Je sais que c'est " un peu en retard " mais juste au cas où quelqu'un aurait besoin de le faire dans syntaxe de la méthode LINQ ( c'est pourquoi j'ai trouvé ce message au départ ), voici comment procéder:
var results = context.Periods
.GroupJoin(
context.Facts,
period => period.id,
fk => fk.periodid,
(period, fact) => fact.Where(f => f.otherid == 17)
.Select(fact.Value)
.DefaultIfEmpty()
)
.Where(period.companyid==100)
.SelectMany(fact=>fact).ToList();
Une autre option valable consiste à répartir les jointures sur plusieurs clauses LINQ , comme suit:
public static IEnumerable<Announcementboard> GetSiteContent(string pageName, DateTime date)
{
IEnumerable<Announcementboard> content = null;
IEnumerable<Announcementboard> addMoreContent = null;
try
{
content = from c in DB.Announcementboards
//Can be displayed beginning on this date
where c.Displayondate > date.AddDays(-1)
//Doesn't Expire or Expires at future date
&& (c.Displaythrudate == null || c.Displaythrudate > date)
//Content is NOT draft, and IS published
&& c.Isdraft == "N" && c.Publishedon != null
orderby c.Sortorder ascending, c.Heading ascending
select c;
//Get the content specific to page names
if (!string.IsNullOrEmpty(pageName))
{
addMoreContent = from c in content
join p in DB.Announceonpages on c.Announcementid equals p.Announcementid
join s in DB.Apppagenames on p.Apppagenameid equals s.Apppagenameid
where s.Apppageref.ToLower() == pageName.ToLower()
select c;
}
//CROSS-JOIN this content
content = content.Union(addMoreContent);
//Exclude dupes - effectively OUTER JOIN
content = content.Distinct();
return content;
}
catch (MyLovelyException ex)
{
throw ex;
}
}