LINQ à SQL-jointure externe gauche avec plusieurs conditions de jointure
j'ai le SQL suivant, que j'essaie 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 la mise en œuvre typique de la jointure externe gauche (c.-à-d. into x from y in x.DefaultIfEmpty()
etc.) mais je ne sais pas comment introduire l'autre condition de jointure ( AND f.otherid = 17
)
MODIFIER
pourquoi la condition AND f.otherid = 17
fait-elle partie de la jointure au lieu de la clause où?
Parce que f
peut ne pas exister pour certains les lignes et je veux encore ces lignes pour être inclus. Si la condition est appliquée dans la clause où, après la jointure - alors je ne comprends pas le comportement que je veux.
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 cherche.
5 réponses
vous devez introduire votre condition d'adhésion avant d'appeler DefaultIfEmpty()
. J'utiliserais simplement 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-commande:
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 colonnes jointures
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 tard " mais juste au cas où quelqu'un doit faire cela dans syntaxe de la méthode LINQ ( c'est pourquoi j'ai trouvé ce post initialement ), ce serait la façon de faire cela:
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 à étaler les jointures sur multiple LINQ clauses , 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;
}
}
il me semble qu'il est utile de considérer certaines réécritures de votre code SQL avant de tenter de le traduire.
personnellement, j'écrirais une telle question comme un syndicat (bien que j'éviterais complètement nulls!):
SELECT f.value
FROM period as p JOIN facts AS f ON p.id = f.periodid
WHERE p.companyid = 100
AND f.otherid = 17
UNION
SELECT NULL AS value
FROM period as p
WHERE p.companyid = 100
AND NOT EXISTS (
SELECT *
FROM facts AS f
WHERE p.id = f.periodid
AND f.otherid = 17
);
donc je suppose que je suis d'accord avec l'esprit de la réponse de @MAbraham1 (bien que leur code semble être sans rapport avec la question).
Cependant, il semble que la requête est expressément conçu pour produire une seule colonne résultat comprenant des lignes en double-double zéros! Il est difficile de ne pas en arriver à la conclusion que cette approche est imparfaite.