2

In the following code:

    var finalArticles =
        from domainArticle in articlesFoundInDomain

        join articleCategoryVersion in dbc.ArticlesCategoriesVersions
            on domainArticle.ArticleID equals articleCategoryVersion.ArticleID
        join articleCategory in dbc.ArticleCategories
            on articleCategoryVersion.CategoryID equals articleCategory.CategoryID

        where articleCategory.ParentID == 52

        group articleCategory by articleCategory.CategoryID
            into newArticleCategoryGroup

I understand that the group clause should be returning an IEnumerable where k is the Key, in this case CategoryID.

I think I'm misunderstanding Linq at this point because I assume that for each 'k' there should be a list of articles in 'v', but I don't understand the mechanisms or terminology or something. When I try to project this statement into a new anonymous object I don't seem to get any articles... where are they?

Edit: Okay so I've got a piece of code that is working, but unfortunately it's hitting the SQL server multiple times:

var articlesAssociatedWithKnowledgeTypes =
                from categories in dbc.ArticleCategories

                join categoryVersions in dbc.ArticlesCategoriesVersions
                    on categories.CategoryID equals categoryVersions.CategoryID

                join articles in articlesFoundInGivenDomain
                    on categoryVersions.ArticleID equals articles.ArticleID

                where categories.ParentID == 52 && articles.Version == categoryVersions.Version

                select new
                {
                    ArticleID = articles.ArticleID,
                    ArticleTitle = articles.Title,
                    ArticleVersion = articles.Version,
                    CategoryID = categories.CategoryID,
                    CategoryName = categories.Name
                } into knowledgeTypesFlat
                group knowledgeTypesFlat by new { knowledgeTypesFlat.CategoryID, knowledgeTypesFlat.CategoryName } into knowledgeTypesNested
                select new
                {
                    CategoryID = knowledgeTypesNested.Key.CategoryID,
                    CategoryName = knowledgeTypesNested.Key.CategoryName,
                    Articles = knowledgeTypesNested.ToList()
                };

I thought the ToList() on Articles would sort that out but it doesn't. But, the code works although I'm not sure if this is optimal?

Jacques
  • 6,936
  • 8
  • 43
  • 102
  • 2
    `join into` is not a Join, but a GroupJoin. It's a combination of joining and grouping – Dennis_E Feb 14 '17 at 17:10
  • Could you show how do you want to project your first query? – ocuenca Feb 14 '17 at 17:14
  • @Dennis_E okay fair enough, so at the end of my first example, what do I need to 'select' in order to get an IEnumerable, or as user InBetween points out IGroup, where K = Category and V = List of Articles associated with K? – Jacques Feb 14 '17 at 17:16
  • @octavioccl what I need is to project IGrouping where 'k' is the category (but it seems it will be the CategoryID only - although I need the name of the category too) and 'v' is the list of articles associated with it. I assumed something like 'select new { CategoryID = newArticleCategoryGroup.Key, Articles = ...}' – Jacques Feb 14 '17 at 17:19
  • Sounds like you need a tutorial on LINQ. This guy explains things very nicely https://www.youtube.com/playlist?list=PL90AF0EFFEF782D27 – Dennis_E Feb 14 '17 at 17:25
  • @Dennis_E yeah I'm running through tutorials at the moment and Jamie King is one of the lot that I'm following. Just trying to get to grips with some of the nuances in Linq. I've been doing a lot of UI work over the last few years, but getting back into C# again – Jacques Feb 14 '17 at 18:05
  • @Jacques Good luck with that. I admit the `join into` / GroupJoin is a little weird. C# and LINQ are awesome, but they can be a little complicated sometimes. – Dennis_E Feb 14 '17 at 19:27
  • http://stackoverflow.com/questions/15595289/linq-to-entities-join-vs-groupjoin/15599143#15599143. But as I said on your previous post: use navigation properties. – Gert Arnold Feb 14 '17 at 20:49

3 Answers3

1

The grouping returns an enumeration of IGroupings. IGrouping<K, V> itself implements IEnumerable<V>. Think of each group as an enumerable of all the members of that group plus an extra property Key

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • 2
    I'm sure it's `IGrouping` which implements `IEnumerable`, not `IGroup` – René Vogt Feb 14 '17 at 17:07
  • @inbetween I'm sure that makes perfect sense to you, but Linq is new'ish to me. I edited my post with another example that does actually work where Employees is accessible, but it's kind of obivous i.e. when I loop through the result of the query expression I have result.Department and result.Employees. How are the two usages of 'into' different? – Jacques Feb 14 '17 at 17:12
  • @RenéVogt yes, fixed it. Thanks. – InBetween Feb 14 '17 at 17:16
0

In your first query you are showing a group by and the second one is a group join, both return different results. The group by returns an IEnumerable<IGrouping<TKey, TElement>>. To get the result you're expecting you could group by CategoryId and CategoryName and project as I show below:

var finalArticles =
    from domainArticle in articlesFoundInDomain
    join articleCategoryVersion in dbc.ArticlesCategoriesVersions
        on domainArticle.ArticleID equals articleCategoryVersion.ArticleID
    join articleCategory in dbc.ArticleCategories
        on articleCategoryVersion.CategoryID equals articleCategory.CategoryID
    where articleCategory.ParentID == 52
    group articleCategory by new{ articleCategory.CategoryID,articleCategory.CategoryName}
        into g
    select new {CatId=g.Key.CategoryID, CatName=g.Key.CategoryName,Articles =g.ToList() };

When you need the grouped elements you can call ToList or ToArray as I did above

ocuenca
  • 38,548
  • 11
  • 89
  • 102
  • @octaviocci I actually tried this yesterday. Interestingly if I loop through Articles of the anonymous type I don't get an article. I seem to get back a category plus an additional property "article.ArticlesCategoriesVersions" which is of type EntitySet. – Jacques Feb 15 '17 at 08:18
0

Your finalArticles query results in a IEnumerable<IGrouping<int, Article>> (assuming CategoryID is int and your articles are of type Article).

These IGrouping<int, Article> provides a Key property of type int (your CategoryID and also the IEnumerable<Article> representing the sequence of articles for that CategoryID.

You can turn this for example into a Dictionary<int, List<Article>> mapping CategoryIDs to the lists of articles:

var dictionary = finalArticles.ToDictionary(group => group.Key, group => group.ToList());

or to a list of categories containing articles:

var categories = finalArticles.Select(group => new { 
                 CategoryID = group.Key, 
                 Articles = group.ToList()}).ToList();

Update after your comment:

var finalArticles =
      from domainArticle in articlesFoundInDomain
      join articleCategoryVersion in dbc.ArticlesCategoriesVersions
           on domainArticle.ArticleID equals articleCategoryVersion.ArticleID
      join articleCategory in dbc.ArticleCategories
           on articleCategoryVersion.CategoryID equals articleCategory.CategoryID

      where articleCategory.ParentID == 52

      group articleCategory by new {articleCategory.CategoryID, articleCategory.Name}
      into newArticleCategoryGroup
      select new 
      { 
          CategoryID = newArticleCategoryGroup.Key.CategoryID,
          CategoryName = newArticleCategoryGroup.Key.Name,
          Articles = newArticleCateGroup.ToList()
      }
René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • I would need the Category ID and Name as well as the list of articles. It looks like you're using Extension methods, could this not be tacked directly onto my query expressions? – Jacques Feb 14 '17 at 17:25
  • @Jacques updated my answer. I'm not so experienced with query syntax and more often use method syntax. Note that query syntax is only a _subset_ of method syntax and gets translated into methods by the compiler. – René Vogt Feb 14 '17 at 17:39