这有点棘手,但是如果您能够实例化新的ImageTag
和Tag
实例以供 linq 使用,则可以在一个大查询中完成。本质上,当你进行外连接时,你必须使用into
关键字 withDefaultIfEmpty(...)
方法来处理“外连接间隙”(例如,在典型的 SQL 左外连接中,连接键的右侧为空时) .
var images = 来自 db.Images 中的 img
在 img.idImage 上的 db.ImageTags 中加入 imgTags 等于 imgTags.idImage
进入外部图像参考
来自outerImageRef.DefaultIfEmpty中的outerIR(new ImageTag() { idImage = img.idImage, idTag = -1 })
在 imgTags.idTag 上的 db.Tags 中加入 t 等于 t.idTag
进入外部RefTags
来自outerRT 中的outerRefTags.DefaultIfEmpty(new Tag(){ idTag=-1, TagName ="untagged"})
通过 externalRT.TagName 将 img 分组到 aGroup
选择新的{
GroupName = aGroup.Key,
项目 = 来自 aGroup 中的 x
选择新的 ImageFragment() {
ImageID = x.idImage,
ScanDate = x.ScanTime
}
};
由于我没有您的确切环境,因此希望以上可以编译,我使用自己的数据类型构建了我的解决方案,然后将其转换为您的问题描述。基本上,关键部分是额外的into
和DefaultIfEmpty
行,如果您从传统的 sql 意义上考虑它,它们基本上有助于将额外的“行”添加到内存中的大规模连接表中。
但是,有一个更易读的解决方案,它不需要 linq 实体的内存实例化(您必须自己将其转换为您的环境):
//第一个查询将返回带有 TagName 和 ImageId 的匿名类型的集合,
// 本质上是加入 ImageTags x-ref 表和标签的关系,这样
//每一行都是标签和图像ID(正如罗伯特哈维在他对你的Q的评论中提到的)
var tagNamesWithImageIds = 来自标签中的标签
在 tag.IdTag 上加入 ImageTags 中的引用等于 refer.IdTag
选择新的{
TagName = tag.Name,
ImageId = 参考.IdImage
};
//现在我们可以通过将图像外部连接到上述关系来获得您的解决方案
// 并再次用“未标记”的匿名类型填充“外部连接间隙”
// 然后最后一次将其与图像表连接起来以进行分组和投影。
var images = 来自图像中的 img
在 img.IdImage 上的 tagNamesWithImageIds 中加入 t 等于 t.ImageId
进入外连接
来自outerJoin.DefaultIfEmpty中的o(新{ TagName =“未标记”,ImageId = img.IdImage })
在 o.ImageId 上的图像中加入 img2 等于 img2.IdImage
o.TagName 将 img2 分组到 aGroup
选择新的{
TagName = aGroup.Key,
Images = aGroup.Select(i => i.Data).ToList() //你肯定需要用你的代码逻辑替换它。我的工作区中只有一个更简单的数据类型。
};
希望这是有道理的。当然,您始终可以将应用程序设置为默认情况下使用“未标记”标记所有内容,或者执行一些更简单的 LINQ 查询来创建 ImageTag 表中不存在的图像 ID 列表,然后联合或其他内容。