LINQ to SQL-Unión externa izquierda con múltiples condiciones de unión
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 unión externa izquierda (ie. 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é es la condición AND f.otherid = 17
parte de la UNIÓN en lugar de en la cláusula WHERE?
Porque f
puede no existir para algunas filas y todavía quiero que estas filas se incluyan. Si la condición se aplica en la cláusula where, después de la ÚNETE - entonces no tengo el comportamiento que quiero.
Desafortunadamente 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 busco.
5 answers
Necesita introducir su condición de unión antes de llamar DefaultIfEmpty()
. Simplemente 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 puedes 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-08 17:03:18
Esto también funciona, ...si tiene múltiples columnas joins
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-16 20:59:24
Sé que es " un poco tarde ", pero por si acaso, si alguien necesita hacer esto en la sintaxis del Método LINQ (es por eso que encontré este post inicialmente ), 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();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-18 17:36:16
Otra opción válida es repartir las uniones entre múltiples cláusulas LINQ, como sigue:
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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-14 19:58:33
Me parece que hay valor en considerar algunas reescrituras a su código SQL antes de intentar traducirlo.
Personalmente, escribiría una consulta como una unión (¡aunque evitaría 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á expresamente diseñada para producir un resultado de una sola columna que comprende filas duplicadas! ¡de hecho, nulos duplicados! Es difícil no llegar a la conclusión de que este enfoque es defectuoso.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-08 13:57:13