【问题标题】:Linq to objects Joining collections and filteringLinq to objects 加入集合和过滤
【发布时间】:2012-03-01 01:34:37
【问题描述】:

我在使用 Linq 过滤/连接内存中的对象列表到对象时遇到了问题,并且对于通常是微不足道的 SQL 查询...

场景:
拥有一个 json 服务(.asmx)允许客户端通过实体框架包装的 sproc(函数导入)进行数据库调用。在这种情况下,[Web 方法]“GetArticles(int [] TagIds)”
我现在正在寻找缓存这些数据以保存数据库调用并将过滤器应用于缓存的集合。

数据:

  • 与 2 个实体的多对多关系:文章、标签
  • 文章可以有很多标签,标签可以关联很多文章,(所以额外的链接表'ArticlesTags')

Web 服务过滤器参数将包含返回的文章可以具有的 TagId 数组。

所以我的基线 SQL 查询看起来像这样

SELECT DISTINCT a.*
FROM Article a INNER JOIN ArticlesTags at ON a.ArticleId = at.ArticleId
WHERE at.TagId in (0, 1.. 'list of tag ids')

我遇到了一些障碍 -
EF 包装的存储过程不允许 SQL 2008(表值参数),因此我无法以首选格式传入 TagId 列表过滤器。 我发现了一个示例,其中可以从一个 sproc 调用返回两个结果集,这可能会解决这个问题。 因此,一旦我有了打算缓存的两个集合(Articles 和 ArticlesTags),如何使用 linq-to-objects 根据可能的 TagId 过滤器参数加入并随后过滤?

【问题讨论】:

    标签: c# linq entity-framework linq-to-objects


    【解决方案1】:

    这是在 LINQ 中“重写”SQL 查询的一种方法:

    class Article {
        public int ArticleId;
        public string ArticleName;
        // Other fields...
    }
    
    class ArticleComparer : IEqualityComparer<Article> {
        public bool Equals(Article x, Article y) {
            return x.ArticleId == y.ArticleId && x.ArticleName == y.ArticleName;
        }
        public int GetHashCode(Article obj) {
            return obj.ArticleId.GetHashCode();
        }
    }
    
    class ArticlesTag {
        public int TagId;
        public int ArticleId;
        // Other fields...
    }
    
    class Program {
    
        static void Main(string[] args) {
    
            // Test data:
    
            var articles = new[] {
                new Article { ArticleId = 1, ArticleName = "Article A" },
                new Article { ArticleId = 2, ArticleName = "Article B" },
                new Article { ArticleId = 3, ArticleName = "Article C" }
            };
    
            var article_tags = new[] {
                new ArticlesTag { TagId = 1, ArticleId = 1 },
                new ArticlesTag { TagId = 2, ArticleId = 1 },
                new ArticlesTag { TagId = 3, ArticleId = 1 },
                new ArticlesTag { TagId = 4, ArticleId = 2 },
                new ArticlesTag { TagId = 5, ArticleId = 2 },
                new ArticlesTag { TagId = 6, ArticleId = 3 },
                new ArticlesTag { TagId = 7, ArticleId = 3 }
            };
    
            var tag_ids = new HashSet<int>(new[] { 2, 3, 6 });
    
            // JOIN "query":
    
            var q = (
                from article in articles
                join article_tag in article_tags
                    on article.ArticleId equals article_tag.ArticleId
                where tag_ids.Contains(article_tag.TagId)
                select article
            ).Distinct(new ArticleComparer());
    
            foreach (var article in q)
                Console.WriteLine(
                    string.Format(
                        "ArticleId = {0}\tArticleName = {1}",
                        article.ArticleId,
                        article.ArticleName
                    )
                );
    
        }
    
    }
    

    打印出来:

    ArticleId = 1   ArticleName = Article A
    ArticleId = 3   ArticleName = Article C
    

    【讨论】:

      【解决方案2】:

      因此,您有一个 Article 表、一个 Tags 表和一个 ArticleTags 表,它们将 Articles ID 与 tags ID 相关联。文章名称是简单的部分。然后,您浏览 ArticleTags 并获取与该文章 ID 匹配的所有 TagID,然后您浏览标签以获取与该标签 ID 关联的名称。将其变成一个简洁的字典,其中键为 TagName,值是 TagNames 的 IEnumerable。 (您可以为 Dictionary 而不是 Dictionary 拉出整个文章和整个标签,只需省略成员选择器。

      var articleDictionary = articles.ToDictionary(
             a => a.Name, // article name is key
             a => ArticleTags
                   .where(t => t.ArticleID == a.Id)
                   .select(t => Tags.Single(tag => tag.id == t.id).TagName // value is an IEnumerable<string> of tag names
      )
      
      foreach (var article in articleDictionary)
      {
          Console.WriteLine(article.Key);
          foreach (var tag in article.Value)
          { 
              Console.WriteLine("\t" + tag)
          }
      }
      

      编辑: 以下是拉动整个对象的方法

      var articleDictionary = articles.ToDictionary(
             a => a,
             a => ArticleTags
                   .where(t => t.ArticleID == a.Id)
                   .select(t => Tags.Single(tag => tag.id == t.id)
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-25
        • 1970-01-01
        • 1970-01-01
        • 2012-03-03
        • 1970-01-01
        • 1970-01-01
        • 2018-03-03
        相关资源
        最近更新 更多