C'est un peu difficile, mais vous pouvez le faire dans une grande requête si vous avez la possibilité d'instancier de nouvelles instances ImageTag
et Tag
pour linq pour travailler avec. Essentiellement, lorsque vous effectuez une jointure externe, vous devez utiliser le mot clé into
avec la méthode DefaultIfEmpty(...)
pour gérer les «écarts de jointure externes» (par exemple, lorsque le côté droit de la clé jointe est null dans un élément externe gauche de SQL standard joindre).
var images = from img in db.Images
join imgTags in db.ImageTags on img.idImage equals imgTags.idImage
into outerImageRef
from outerIR in outerImageRef.DefaultIfEmpty(new ImageTag() { idImage = img.idImage, idTag = -1 })
join t in db.Tags on imgTags.idTag equals t.idTag
into outerRefTags
from outerRT in outerRefTags.DefaultIfEmpty(new Tag(){ idTag=-1, TagName ="untagged"})
group img by outerRT.TagName into aGroup
select new {
GroupName = aGroup.Key,
Items = from x in aGroup
select new ImageFragment() {
ImageID = x.idImage,
ScanDate = x.ScanTime
}
};
Espérons que les compiles ci-dessus puisque je n'ai pas votre environnement exact, je construit ma solution en utilisant mes propres types de données, puis converti à la description de votre question. Fondamentalement, les parties clés sont les lignes supplémentaires into
et DefaultIfEmpty
qui aident essentiellement à ajouter les «rangées» supplémentaires dans la table massivement jointe qui est en mémoire si vous y pensez dans le sens traditionnel de sql.
Cependant, il y a une solution plus lisible qui ne nécessite pas la mémoire instanciation des entités LINQ (vous devrez convertir celui-ci vous à votre environnement):
//this first query will return a collection of anonymous types with TagName and ImageId,
// essentially a relation from joining your ImageTags x-ref table and Tags so that
// each row is the tag and image id (as Robert Harvey mentioned in his comment to your Q)
var tagNamesWithImageIds = from tag in Tags
join refer in ImageTags on tag.IdTag equals refer.IdTag
select new {
TagName = tag.Name,
ImageId = refer.IdImage
};
//Now we can get your solution by outer joining the images to the above relation
// and filling in the "outer join gaps" with the anonymous type again of "untagged"
// and then joining that with the Images table one last time to get your grouping and projection.
var images = from img in Images
join t in tagNamesWithImageIds on img.IdImage equals t.ImageId
into outerJoin
from o in outerJoin.DefaultIfEmpty(new { TagName = "untagged", ImageId = img.IdImage })
join img2 in Images on o.ImageId equals img2.IdImage
group img2 by o.TagName into aGroup
select new {
TagName = aGroup.Key,
Images = aGroup.Select(i => i.Data).ToList() //you'll definitely need to replace this with your code's logic. I just had a much simpler data type in my workspace.
};
espoir qui fait sens. Bien sûr, vous pouvez toujours définir votre application pour tout marquer par défaut w/"non étiqueté" ou faire des requêtes LINQ beaucoup plus simples pour créer une liste d'ID d'image qui ne sont pas présents dans votre table ImageTag, puis union ou quelque chose.
J'ai réussi à comprendre sans voir cela, mais cela aurait été utile jamais moins. – Boarder2