2

给定以下数据库结构 替代文本 http://dl.dropbox.com/u/26791/tables.png

我正在尝试编写一个 LINQ 查询,该查询将返回按与其关联的标签分组的图像。到目前为止,我有这个:

var images = from img in db.Images
    join imgTags in db.ImageTags on img.idImage equals imgTags.idImage
    join t in db.Tags on imgTags.idTag equals t.idTag
    where img.OCRData.Contains(searchText.Text)
    group img by new { t.TagName } into aGroup
    select new
    {
        GroupName = aGroup.Key.TagName,
        Items = from x in aGroup
        select new ImageFragment()
        {
             ImageID = x.idImage,
             ScanDate = x.ScanTime
        }
    };

效果很好。但是,我还想返回一组“(未标记)”或其他内容中没有任何标签的图像。如果不为每个图像插入默认标签,我就无法理解如何做到这一点,这似乎通常不是一个很好的解决方案。

4

3 回答 3

1

如果在没有对应的标签记录的情况下想要图像记录,则需要对图像标签表进行
外连接。

于 2010-04-02T02:08:32.470 回答
0

这就是我最终做的事情。我还没有真正检查过这会生成什么样的 SQL,我猜它可能并不完全漂亮。我认为我最好自己做几个查询并汇总这些东西,但无论如何这都有效:

var images = from img in db.Images
                     join imgTags in db.ImageTags on img.idImage equals imgTags.idImage into g
                     from imgTags in g.DefaultIfEmpty()
                     join t in db.Tags on imgTags.idTag equals t.idTag into g1
                     from t in g1.DefaultIfEmpty()
                     where img.OCRData.Contains(searchText.Text)
                     group img by t == null ? "(No Tags)" : t.TagName into aGroup
                     select new
                    {
                        GroupName = aGroup.Key,
                        Items = from x in aGroup
                                        select new ImageFragment()
                                        {
                                            ImageID = x.idImage,
                                            ScanDate = x.ScanTime
                                        }
                    };
于 2010-04-03T05:41:56.807 回答
0

这有点棘手,但是如果您能够实例化新的ImageTagTag实例以供 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
             }
     };

由于我没有您的确切环境,因此希望以上可以编译,我使用自己的数据类型构建了我的解决方案,然后将其转换为您的问题描述。基本上,关键部分是额外的intoDefaultIfEmpty行,如果您从传统的 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 列表,然后联合或其他内容。

于 2010-04-02T21:55:05.983 回答