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