запрос linq для системы тегов - поиск нескольких тегов - PullRequest
4 голосов
/ 13 ноября 2009

У меня есть две таблицы: теги (tagid, postid, tagname) и сообщения (postid, name, ...)
Теперь я хочу сделать запрос, который возвращает мне все сообщения, которые имеют общее количество тегов. как: я хочу все сообщения, которые имеют тег asp.net и jquery

Как я уже сказал, количество тегов для поиска является общим

как я могу сделать что-то подобное?

ТНХ

обновление 17.11.2009: Существует одна проблема: связь между таблицами не существует, потому что мой первичный ключ на 2 поля (для управления версиями), как я могу сделать это без отношения? Я использую Linq To Entities

также, запрос должен иметь хорошую производительность и не должен делать тысячи запросов к серверу.

Ответы [ 4 ]

6 голосов
/ 13 ноября 2009

Вы не говорите, используете ли вы L2S, L2O, L2E или что. Итак, вот метод расширения, который работает для всех из них. Я делаю некоторые предположения о расположении ваших объектов, поэтому вам, возможно, придется исправить это.

public static IQueryable<Post> WhereHasAllTags(this IQueryable<Post> posts, IEnumerable<string> tags)
{
    var q = posts;
    foreach (var tag in tags)
    {
        q = q.Where(p => p.Tags.Any(t => t.Name == tag));
    }
    return q;
}

Теперь используйте его:

var filtered = Context.Posts.WhereHasAllTags(new [] { "asp.net", "jquery" } );
4 голосов
/ 13 ноября 2009

Лучше всего заглянуть в LinqKit для динамического построения предикатов. Это позволит вам объединить несколько предикатов вместе, так что вы просто зациклите теги, чтобы создать окончательное выражение.

Существуют особые соображения, если вы используете Entity Framework вместо Linq2SQL, поэтому опубликовать определенный код немного сложно, но примеров на этой странице должно быть достаточно, чтобы указать правильное направление.

1 голос
/ 20 ноября 2009

Я думаю, вы не можете использовать .Contains () с использованием EF 3.5, с которым у меня возникла проблема. Я обошел это с помощью этого расширения "WhereIn"

Обходной путь 'Contains ()' с использованием Linq to Entities?

поместите это в статический класс, тогда вы можете использовать что-то вроде:

IQueryable<Post> PostsWithByTags(IEnumerable<string> tagNames)
{
    var postIds = context.Tags.Select(t=>t.postid); 

    foreach (var tag in tagNames)
    {
       postIds = context.Tags
                     .WhereIn(t=> t.postid, postIds)
                     .Where(t=>t.tagname == tag);
    }

    return context.Tags.Where( t=> t.posId, postIds)
}

Я действительно думаю, что вы должны смотреть на отношения между вашими таблицами.

1 голос
/ 13 ноября 2009
IQueryable<Post> FilterByTags(IQueryable<Post> posts, IEnumerable<Tag> tags)
{
    foreach (var tag in tags)
    {
        posts = posts.Where(post => post.Tags.Contains(tag));
    }
    return posts;
}

В IQueryable<Post>, который вы передадите, будут добавлены фильтры, чтобы он ссылался на каждый Tag в списке.

Это общая реализация, которую вам, возможно, придется настроить в зависимости от вашего поставщика LINQ

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