【问题标题】:linq query for tag system - search for multiple tags标签系统的 linq 查询 - 搜索多个标签
【发布时间】:2009-11-13 16:22:37
【问题描述】:

我有两个表,Tags(tagid, postid, tagname) 和 posts(postid, name, ...)
现在我想做一个查询,返回所有具有通用标签数量的帖子。 比如:我想要所有带有标签 asp.net 和 jquery 的帖子

正如我所说,要查找的标签数量是通用的

我该怎么做?

谢谢

2009 年 11 月 17 日更新: 有一个问题:表之间的关系不存在,因为我的主键在 2 个字段上(用于版本控制)我怎样才能使它没有关系? 我正在使用 Linq To 实体

此外,查询应该具有良好的性能,并且不应发出数千个服务器请求。

【问题讨论】:

    标签: asp.net linq tags


    【解决方案1】:

    您不会说您使用的是 L2S、L2O、L2E 还是什么。所以这是一个适用于所有这些的扩展方法。我正在对您的对象的布局进行一些猜测,因此您可能需要更正其中的一些。

    public static IQueryable<Post> WhereHasAllTags(this IQueryable<Post> posts, IEnumerable<string> tags)
    {
        var q = posts;
        foreach (var tag in tags)
        {
            q = q.Where(p => p.Tags.Any(t => t.Name == tag));
        }
        return q;
    }
    

    现在使用它:

    var filtered = Context.Posts.WhereHasAllTags(new [] { "asp.net", "jquery" } );
    

    【讨论】:

    • 这看起来像我需要的,但有一个问题:表之间的关系不存在,因为我的主键在 2 个字段上(用于版本控制)我怎样才能使它没有关系? (我使用 EF 顺便说一句)
    • 很难在没有看到元数据的情况下回答这个问题。想要将其作为一个单独的问题发布并提供更多信息?
    • 你可以在 EF 中做一个“加入”,这样你就可以“伪造”一个关系。
    • Jan,这将放弃关系的所有好处,以及使模型错误。最好从一开始就让模型正确。
    • 没有FK关系可能有一些原因,主要是性能。所以它是相当可行的。无论如何,+1,因为这似乎是最体面的解决方案。
    【解决方案2】:

    最好的办法是查看LinqKit 以动态构建谓词。这将允许您将多个谓词连接在一起,因此您只需遍历标签以构建最终表达式。

    如果您使用的是 Entity Framework 与 Linq2SQL,则需要特别注意,因此发布具体代码有点困难,但该页面上的示例应该足以为您指明正确的方向。

    【讨论】:

      【解决方案3】:

      我猜你不能在我遇到问题的 EF 3.5 中使用 .Contains() 。我通过使用这个“WhereIn”扩展解决了这个问题

      'Contains()' workaround using Linq to Entities?

      把它放到一个静态类中,然后你可以使用类似的东西:

      IQueryable<Post> PostsWithByTags(IEnumerable<string> tagNames)
      {
          var postIds = context.Tags.Select(t=>t.postid); 
      
          foreach (var tag in tagNames)
          {
             postIds = context.Tags
                           .WhereIn(t=> t.postid, postIds)
                           .Where(t=>t.tagname == tag);
          }
      
          return context.Tags.Where( t=> t.posId, postIds)
      }
      

      我真的认为你应该看看你的表之间的关系。

      【讨论】:

        【解决方案4】:
        IQueryable<Post> FilterByTags(IQueryable<Post> posts, IEnumerable<Tag> tags)
        {
            foreach (var tag in tags)
            {
                posts = posts.Where(post => post.Tags.Contains(tag));
            }
            return posts;
        }
        

        您传入的IQueryable&lt;Post&gt; 将添加过滤器,以确保它引用列表中的每个Tag

        这是一个通用实现,您可能需要根据您的 LINQ 提供程序进行调整

        【讨论】:

        • 您确实意识到这段代码什么都不做?这是一种只有一个副作用的 void 方法:枚举tags
        • 好点,自从我使用 LINQ 已经有一段时间了,它是不可变的,不是吗。
        • 欺骗你的不是不变性本身。是延期执行。调用Where 不会执行任何查询,而是会“创建”一个查询。只有当您稍后枚举它时(使用foreachToListToArray 或其他东西)才会运行查询。
        • 如果您在谷歌上搜索“LINQ 延迟执行”,您将获得足够的资源来理解这一点。
        猜你喜欢
        • 2012-02-04
        • 1970-01-01
        • 1970-01-01
        • 2011-01-04
        • 1970-01-01
        • 2016-09-10
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多