JOIN e LEFT JOIN equivalente em LINQ
Pergunta
Eu estou trabalhando com a seguinte consulta SQL:
SELECT
a.AppointmentId,
a.Status,
a.Type,
a.Title,
b.Days,
d.Description,
e.FormId
FROM Appointment a (nolock)
LEFT JOIN AppointmentFormula b (nolock)
ON a.AppointmentId = b.AppointmentId and b.RowStatus = 1
JOIN Type d (nolock)
ON a.Type = d.TypeId
LEFT JOIN AppointmentForm e (nolock)
ON e.AppointmentId = a.AppointmentId
WHERE a.RowStatus = 1
AND a.Type = 1
ORDER BY a.Type
Não tenho a certeza como conseguir o JOINs em LINQ. Todas as minhas tabelas têm relações de chave estrangeira.
Solução
Você pode ter que ajustar isso um pouco como eu estava indo de improviso, mas há um par de coisas importantes para manter em mente. Se você tiver seus relacionamentos configurado corretamente em seu dbml, você deve ser capaz de fazer junções internas implicitamente e apenas acessar os dados por meio de sua tabela inicial. Além disso, esquerda junta-se em LINQ não tão simples são como podemos esperar e você tem que ir através da sintaxe DefaultIfEmpty, a fim de fazer isso acontecer. Eu criei um tipo anônimo aqui, mas você pode querer colocar em uma classe DTO ou algo nesse sentido. Eu também não sabia o que queria fazer no caso de valores nulos, mas você pode usar o ?? sintaxe para definir um valor para dar a variável se o valor for nulo. Deixe-me saber se você tem perguntas adicionais ...
var query = (from a in context.Appointment
join b in context.AppointmentFormula on a.AppointmentId equals b.AppointmentId into temp
from c in temp.DefaultIfEmpty()
join d in context.AppointmentForm on a.AppointmentID equals e.AppointmentID into temp2
from e in temp2.DefaultIfEmpty()
where a.RowStatus == 1 && c.RowStatus == 1 && a.Type == 1
select new {a.AppointmentId, a.Status, a.Type, a.Title, c.Days ?? 0, a.Type.Description, e.FormID ?? 0}).OrderBy(a.Type);
Outras dicas
SELECT A.X, B.Y
FROM A JOIN B ON A.X = B.Y
Esta chamada de método LINQ (para entrar) irá gerar a acima Unir.
var query = A.Join
(
B,
a => a.x,
b => b.y,
(a, b) => new {a.x, b.y} //if you want more columns - add them here.
);
SELECT A.X, B.Y
FROM A LEFT JOIN B ON A.X = B.Y
Estas chamadas de método LINQ (para GroupJoin, SelectMany, DefaultIfEmpty) irá produzir o acima Esquerda Junte-se
var query = A.GroupJoin
(
B,
a => a.x,
b => b.y,
(a, g) => new {a, g}
).SelectMany
(
z => z.g.DefaultIfEmpty(),
(z, b) =>
new { x = z.a.x, y = b.y } //if you want more columns - add them here.
);
O conceito chave aqui é que os métodos de Linq produzir resultados hierarquicamente em forma, não achatada formas linha-coluna.
-
GroupBy
de Linq produz resultados em forma de uma hierarquia com uma chave de agrupamento corresponde a umrecolha > forte de elementos (o qual pode não estar vazia). cláusula GroupBy
de SQL produz uma chave de agrupamento com valores agregados -. não há sub-coleção para o trabalho com - Da mesma forma,
GroupJoin
de Linq produz uma forma hierárquica - um registro pai corresponde a um coleção de registros filho (que pode ser vazia).LEFT JOIN
do Sql produz um registro pai combinados para cada registro de criança, ou um registro filho nulo se não houver outras partidas. Para chegar à forma do Sql de forma de Linq, é preciso descompactar o conjunto de registros filho comSelectMany
- e lidar com coleções vazias de registros filho usandoDefaultIfEmpty
.
E aqui está a minha tentativa de linquifying que sql na pergunta:
var query =
from a in Appointment
where a.RowStatus == 1
where a.Type == 1
from b in a.AppointmentFormula.Where(af => af.RowStatus == 1).DefaultIfEmpty()
from d in a.TypeRecord //a has a type column and is related to a table named type, disambiguate the names
from e in a.AppointmentForm.DefaultIfEmpty()
order by a.Type
select new { a.AppointmentId, a.Status, a.Type, a.Title, b.Days, d.Description, e.Form }
Se você quiser preservar as dicas (NOLOCK), eu tenho blog uma solução acessível usando métodos de extensão em C #. Note-se que este é o mesmo que adicionar dicas NOLOCK para cada tabela na consulta.