【问题标题】:Using LINQ-To-Entities to Generate Information使用 LINQ-To-Entities 生成信息
【发布时间】:2010-05-20 19:39:09
【问题描述】:

我正在开发一个网站,用户可以在该网站上为他们发布的书籍添加标签,就像目前在 Stack Overflow 上针对问题所做的那样。

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 中为实体查询写一些东西,根据标签为我提供数据:

    查询bookIds where tagid = 1
    返回bookid: 113421, 113422

    查询 2tags 1 and 2
    返回113421

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

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

第二种情况

RelatedTags
Tag Count
3   1
4   1

如何在 LINQ 中执行此操作?

【问题讨论】:

    标签: c# .net asp.net-mvc linq linq-to-entities


    【解决方案1】:

    在第一部分,有趣的限制是书必须匹配输入的每个标签,因此“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;
    

    这基本上执行从书籍到 booktags 以及所选标签 ID 列表的连接,并将选择限制为 book->tag 匹配的计数等于所选标签 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()
                        };
    

    快速示例的完整代码。不完全是 OOP,但你明白了。

    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,您将获得图书 A,相关标签将是 3 (CSS) 和 4 (VB)。

    【讨论】:

    • 现在需要获取相关标签。
    【解决方案2】:

    只需在 1:N 或 1:1 关系中映射表的外键,并让设计器为您创建导航属性。 (Books:BooksTags 将 1:N 从 Books.BookID 映射到 BooksTags.BookID,BooksTags.TagID 将 1:1 映射到 Tags.TagID)。这实际上是一种伪装的 N:M 关系。我不知道设计师是否直接选择了这个,但是通过一些摆弄你可以得到正确的导航属性。

    现在回答问题:

    1. model.Tags.Where(t =&gt; t.ID == 1).Books.Select(b =&gt; b.ID)

    2. 获取一本书的所有标签,并在 BooksTags 上加入该表,这样您就可以简单地使用 Count() 来获取计数。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-07
        相关资源
        最近更新 更多