Использование LINQ-To-Entities для генерации информации - PullRequest
1 голос
/ 20 мая 2010

Я работаю над веб-сайтом, где пользователь может добавлять теги к своим опубликованным книгам, так же, как в настоящее время делается для вопросов о переполнении стека.

Классы

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

    Запрос 2 : tags 1 and 2
    Возвращает : 113421

  2. Мне нужны теги и их количество для отображения в связанных тегах, поэтому в первом случае Мой класс связанных тегов должен иметь следующий результат.

    RelatedTags Количество тегов 2 1 3 1 4 2 8 1

Второй случай :

RelatedTags
Tag Count
3   1
4   1

Как мне это сделать в LINQ?

Ответы [ 3 ]

0 голосов
/ 21 мая 2010

В первой части интересным ограничением является то, что книга должна соответствовать каждому введенному тегу, поэтому предложение where из «где tagid == someId» на самом деле не сработает. Я представляю что-то вроде этого (пример 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;

Который в основном выполняет объединение книг с закладками, а также со списком выбранных идентификаторов тегов и ограничивает выбор, где количество совпадений book-> tag равно количеству выбранных идентификаторов тегов.

Чтобы вытащить связанные теги, может быть что-то вроде этого

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 вы получите книгу A, и связанные теги будут 3 (CSS) и 4 (VB).

0 голосов
/ 21 мая 2010

Это не имеет прямого отношения к ответу как таковому, но, возможно, вы захотите взглянуть на linqpad , поскольку это поможет вам создавать операторы L2S непосредственно из вашей базы данных.

0 голосов
/ 21 мая 2010

Просто сделайте внешние ключи, отображающие таблицы в отношениях 1: N или 1: 1, и позвольте дизайнеру создать свойства навигации для вас. (Книги: BooksTags отображает 1: N из Books.BookID в BooksTags.BookID, а BooksTags.TagID отображает 1: 1 в Tags.TagID). На самом деле это замаскированное отношение N: M. Я не знаю, подхватит ли дизайнер это напрямую, но с некоторыми неудобствами вы можете получить правильные свойства навигации.

Теперь по вопросам:

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

  2. Получите все теги, имеющиеся для книги, и присоединитесь к этой таблице на BooksTags, этим вы можете просто использовать Count (), чтобы получить счет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...