Comment puis-je exprimer le plus élégamment la jointure gauche avec l'agrégat SQL en tant que requête LINQ
Question
SQL :
SELECT
u.id,
u.name,
isnull(MAX(h.dateCol), '1900-01-01') dateColWithDefault
FROM universe u
LEFT JOIN history h
ON u.id=h.id
AND h.dateCol<GETDATE()-1
GROUP BY u.Id, u.name
La solution
Une solution, même si elle reporte la gestion de la valeur nulle au code, pourrait être :
DateTime hier = DateTime.Now.Date.AddDays(-1);
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
Cela ne produit pas exactement le même SQL, mais fournit le même résultat logique.Traduire des requêtes SQL « complexes » en LINQ n'est pas toujours simple.
Autres conseils
var collection=
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate =(DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
Utilisez simplement le code ci-dessus et cela devrait fonctionner correctement !
Ce n'est pas une réponse complète pour vous, mais sur la pièce de jointure de gauche, vous pouvez utiliser l'opérateur DefaultIfEmpty comme ceci :
var collection =
from u in db.Universe
join history in db.History on u.id = history.id into temp
from h in temp.DefaultIfEmpty()
where h.dateCol < DateTime.Now.Date.AddDays(-1)
select u.id, u.name, h.dateCol ?? '1900-01-01'
Je n'ai pas encore eu besoin d'exécuter des commandes groupby, j'ai donc laissé cela de côté pour ne pas vous envoyer sur le mauvais chemin.Deux autres choses rapides à noter.Je n'ai pas pu me joindre sur deux paramètres, bien que, comme ci-dessus, il existe des moyens de contourner ce problème.Également ??L'opérateur fonctionne très bien à la place de isnull dans SQL.
Vous allez vouloir utiliser le join into
construct pour créer une requête de groupe.
TestContext db = new TestContext(CreateSparqlTripleStore());
var q = from a in db.Album
join t in db.Track on a.Name equals t.AlbumName into tracks
select new Album{Name = a.Name, Tracks = tracks};
foreach(var album in q){
Console.WriteLine(album.Name);
foreach (Track track in album.Tracks)
{
Console.WriteLine(track.Title);
}
}