web-dev-qa-db-fra.com

LINQ to SQL - Jointure externe gauche avec plusieurs conditions de jointure

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.

143
dan

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
235
dahlbyk

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
25
ZenXavier

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();
11
Prokurors

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;
    }
}
5
MAbraham1