right mvc multiple left ejemplos c# sql linq linq-to-sql outer-join

mvc - linq join c# ejemplos



LINQ to SQL-Unión externa izquierda con múltiples condiciones de unión (5)

Tengo el siguiente SQL, que estoy tratando de traducir a 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

He visto la implementación típica de la combinación externa izquierda (es decir, into x from y in x.DefaultIfEmpty() etc.) pero no estoy seguro de cómo introducir la otra condición de unión ( AND f.otherid = 17 )

EDITAR

¿Por qué la AND f.otherid = 17 parte de JOIN en lugar de en la cláusula WHERE? Porque f puede no existir para algunas filas y aún quiero que se incluyan estas filas. Si la condición se aplica en la cláusula WHERE, después de JOIN, entonces no obtengo el comportamiento que deseo.

Lamentablemente esto:

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

parece ser equivalente a esto:

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

que no es exactamente lo que estoy buscando.


Me parece que es útil considerar algunas reescrituras en su código SQL antes de intentar traducirlo.

Personalmente, escribiría una consulta como una unión (¡aunque evitaría los nulos por completo!):

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 );

Así que supongo que estoy de acuerdo con el espíritu de la respuesta de @ MAbraham1 (aunque su código parece no estar relacionado con la pregunta).

Sin embargo, parece que la consulta está diseñada expresamente para producir un resultado de una sola columna que comprenda filas duplicadas, de hecho nulos duplicados. Es difícil no llegar a la conclusión de que este enfoque es defectuoso.


Otra opción válida es dividir las uniones en múltiples cláusulas LINQ , de la siguiente manera:

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


Sé que es " un poco tarde ", pero por si acaso alguien necesita hacer esto en la sintaxis del Método LINQ ( que es la razón por la que encontré esta publicación al principio ), esta sería la forma de hacerlo:

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


esto también funciona, ... si tienes varias columnas se une

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


DefaultIfEmpty() introducir su condición de combinación antes de llamar a DefaultIfEmpty() . Solo usaría la sintaxis del método de extensión:

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

O puede usar una subconsulta:

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