2012-03-01 2 views
2

Я имеющие проблемы фильтрации/присоединение в памяти списков объектов с Linq к объектам, а также за то, что, как правило, тривиальным запрос SQL ...Linq к объектам Возьмутся коллекция и фильтрации

Сценарий:
Имейте json-сервис (.asmx), позволяющий клиенту выполнить вызов БД через Entity Framework, завернутый sproc (импорт функции). В этом случае [Веб-метод] «GetArticles (int [] TagIds)»
Теперь я хочу кэшировать эти данные, чтобы сохранять вызовы БД и применять фильтры к кешированной коллекции.

данные:

  • Многие ко многим отношений с 2 ​​субъектами: Статьи Метки
  • Статей могут иметь много тэгов, и метки могут быть связаны со многими статьями, (так дополнительной таблица ссылки «ArticlesTags»)

Параметр фильтра веб-службы будет содержать массив 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 завернутые sprocs не позволяют SQL 2008 (таблица значений параметров), так что я не могу перейдите в фильтр списка TagId в предпочтительном формате. Я нашел пример, когда два набора результатов могут быть возвращены из одного вызова sproc, который может обойти это. Итак, как только у меня есть две коллекции (статьи и статьи), которые я намерен кэшировать, как можно объединить и затем фильтровать на основе возможного параметра фильтра TagId с помощью linq-to-objects?

ответ

1

Вот один из способов "переписать" свой SQL запрос в LINQ:

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 
+0

Отличная работа, именно то, что я искал! –

1

Так у вас есть статьи таблицы, таблицу тегов, и таблица ArticleTags который связывает идентификатор статьи с идентификатором тегов. Название статьи - легкая часть. Затем вы проходите через ArticleTags и получаете все теги TagID, которые соответствуют этому идентификатору статей, затем вы просматриваете теги, чтобы получить имя, связанное с этим идентификатором тега. Включает его в один опрятный словарь с тегом TagName для ключа, а значение представляет собой строку IEnumerable <> тегов TagNames. (Вы могли бы вытащить всю статью и весь тег для словаря < статьи, Tag> вместо словаря < строки, строка> просто выйти из селектора член

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) 
    } 
} 

Edit:. Вот как бы вытащить все объекты

var articleDictionary = articles.ToDictionary(
     a => a, 
     a => ArticleTags 
      .where(t => t.ArticleID == a.Id) 
      .select(t => Tags.Single(tag => tag.id == t.id) 
) 
Смежные вопросы