代码之家  ›  专栏  ›  技术社区  ›  Parminder

使用LINQ to实体生成信息

  •  1
  • Parminder  · 技术社区  · 15 年前

    我正在一个网站上工作,在那里用户可以向他们的已发布的书籍添加标签,就像目前在处理堆栈溢出问题时所做的那样。

    :

    Books
    {
    bookId,
    Title
    }
    
    Tags
    {
    Id
    Tag
    }
    
    BooksTags
     {
     Id
     BookId
     TagId
     }
    

    这是一些样本记录。

    Books
    BookId Title
    113421  A
    113422  B
    
    Tags
    Id Tag
    1  ASP 
    2  C#
    3  CSS
    4  VB
    5  VB.NET
    6  PHP
    7  java
    8  pascal
    
     BooksTags   
     Id  BookId  TagId
     1  113421    1
     2  113421    2
     3  113421    3
     4  113421    4
     5  113422    1
     6  113422    4
     7  113422    8
    

    问题

    1. 我需要在linq-to-entity查询中编写一些东西,这些查询根据标记为我提供数据:

      查询 : bookIds where tagid = 1
      退换商品 : bookid: 113421, 113422

      查询2 : tags 1 and 2
      退换商品 : 113421

    2. 我需要在相关标签中显示标签及其计数,所以在第一种情况下 我的相关标签类应该有以下结果。

      相关标签 标记计数 2 1 3 1 4 2 8 1

    第二例 :

    RelatedTags
    Tag Count
    3   1
    4   1
    

    我该如何在Linq中做到这一点?

    3 回复  |  直到 15 年前
        1
  •  0
  •   Anthony Pegram    15 年前

    在第一部分,有趣的限制是书必须匹配输入的每个标记,所以“where tagid==someid”的where子句不会真正起作用。我设想类似这样的事情(Linq to Objects示例)

    List<int> selectedTagIds = new List<int>() { 1, 2 };
    var query = from book in books
                join booktag in booktags 
                on book.Id equals booktag.BookId 
                join selectedId in selectedTagIds 
                on booktag.TagId equals selectedId 
                group book by book into bookgroup 
                where bookgroup.Count() == selectedTagIds.Count
                select bookgroup.Key;
    

    它基本上执行从书籍到书签以及所选标记ID列表的联接,并将所选内容限制为书籍计数与所选标记ID计数匹配的位置。

    去拉相关的标签,也许是这样的

    var relatedTags = from book in query // use original query as base
                        join booktag in booktags
                        on book.Id equals booktag.BookId
                        join tag in tags
                        on booktag.TagId equals tag.Id
                        where !selectedTagIds.Contains(tag.Id) // exclude selected tags from related tags
                        group tag by tag into taggroup
                        select new
                        {
                            Tag = taggroup.Key,
                            Count = taggroup.Count()
                        };
    

    快速示例的完整代码。不是很糟糕,但你明白了。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace StackOverflow
    {
        class Program
        {
            static void Main()
            {
                List<Book> books = new List<Book>() 
                {
                    new Book() { Id = 113421, Title = "A" },
                    new Book() { Id = 113422, Title = "B" }
                };
    
                List<Tag> tags = new List<Tag>()
                {
                    new Tag() { Id = 1, Name = "ASP" },
                    new Tag() { Id = 2, Name = "C#" },
                    new Tag() { Id = 3, Name = "CSS" },
                    new Tag() { Id = 4, Name = "VB" },
                    new Tag() { Id = 5, Name = "VB.NET" },
                    new Tag() { Id = 6, Name = "PHP" },
                    new Tag() { Id = 7, Name = "Java" },
                    new Tag() { Id = 8, Name = "Pascal" }
                };
    
                List<BookTag> booktags = new List<BookTag>()
                {
                    new BookTag() { Id = 1, BookId = 113421, TagId = 1 },
                    new BookTag() { Id = 2, BookId = 113421, TagId = 2 },
                    new BookTag() { Id = 3, BookId = 113421, TagId = 3 },
                    new BookTag() { Id = 4, BookId = 113421, TagId = 4 },
                    new BookTag() { Id = 5, BookId = 113422, TagId = 1 },
                    new BookTag() { Id = 6, BookId = 113422, TagId = 4 },
                    new BookTag() { Id = 7, BookId = 113422, TagId = 8 }
                };
    
    
                List<int> selectedTagIds = new List<int>() { 1,2 };
    
                // get applicable books based on selected tags
    
                var query = from book in books
                            join booktag in booktags
                            on book.Id equals booktag.BookId
                            join selectedId in selectedTagIds
                            on booktag.TagId equals selectedId
                            group book by book into bookgroup
                            where bookgroup.Count() == selectedTagIds.Count
                            select bookgroup.Key;
    
                foreach (Book book in query)
                {
                    Console.WriteLine("{0}\t{1}",
                        book.Id,
                        book.Title);
                }
    
                // get related tags for selected tags
    
                var relatedTags = from book in query // use original query as base
                                  join booktag in booktags
                                  on book.Id equals booktag.BookId
                                  join tag in tags
                                  on booktag.TagId equals tag.Id
                                  where !selectedTagIds.Contains(tag.Id) // exclude selected tags from related tags
                                  group tag by tag into taggroup
                                  select new
                                  {
                                      Tag = taggroup.Key,
                                      Count = taggroup.Count()
                                  };
    
                foreach (var relatedTag in relatedTags)
                {
                    Console.WriteLine("{0}\t{1}\t{2}",
                        relatedTag.Tag.Id,
                        relatedTag.Tag.Name,
                        relatedTag.Count);
                }
    
                Console.Read();
            }
        }
    
        class Book
        {
            public int Id { get; set; }
            public string Title { get; set; }
        }
    
        class Tag
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    
        class BookTag
        {
            public int Id { get; set; }
            public int BookId { get; set; }
            public int TagId { get; set; }
        } 
    }
    

    因此,对于选定的标记1&2,您将得到BookA,相关的标记将是3(css)和4(vb)。

        2
  •  0
  •   Femaref    15 年前

    只需使用外键映射1:n或1:1关系中的表,并让设计器为您创建导航属性。(books:books tags映射1:n从books.bookid到books tags.bookid,books tags.tagid映射1:1到tags.tagid)。这实际上是一种伪装的N:M关系。我不知道设计师是否直接接受了这个,但是通过一些修改,你可以得到正确的导航属性。

    现在请回答以下问题:

    1. model.Tags.Where(t => t.ID == 1).Books.Select(b => b.ID)

    2. 获取一本书的所有标签,并将该表加入到bookstags中,通过这个,您可以简单地使用count()来获取计数。

        3
  •  0
  •   griegs    15 年前

    这与答案没有直接关系,但您可能想看看 linqpad 因为它将帮助您直接从数据库构建L2S语句。

    推荐文章