2015-06-22 2 views
5

У меня есть следующие 2 сущности в моем db.Содержит по крайней мере все в структуре Entity

public class Article 
{ 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    // Some code removed for brevity 

    public virtual ICollection<Tag> Tags { get; set; } 
} 


public class Tag 
{ 

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    // Some code removed for brevity 

    public virtual ICollection<Article> Articles { get; set; } 

} 

Мне нужно отфильтровать эти статьи на основе идентификаторов тегов, которые переданы в мое действие.

public ActionResult FindAll(List<int> tags) 
{ 

    // 
    // I need to return all articles which have ALL the tags passed into this method 
    // 

    var query = ApplicationDbContext.Articles... 


} 

Например, если я прошел в 1, 2, 3 в действие, только статьи, которые имели эти 3 метки или больше будут возвращены.

Как я могу это достичь?

Спасибо за отличный ответ!

Все ваши ответы дали правильный результат, поэтому я сделал быстрое, базовое профилирование в sql, и это были результаты, основанные на ваших запросах.

Query Results

+0

Для тех '' All' ответы Except' и, вы можете проверить, чтобы убедиться, что производительность является приемлемой для нагрузки вы ожидали, и что сгенерированный SQL все еще работает, если 'tags.Count' большой. См. Комментарии в разделе [this] (http://stackoverflow.com/questions/30947278/ef-intersect-syntax/30948394#comment49949396_30947688) для более подробной информации. Это может стоить запросить надмножество статей (с любыми тегами?) И дальнейшей фильтрации. – jjj

+0

Если ни один из ответов не работал или вы все еще сталкиваетесь с проблемами, сообщите мне, чтобы я мог помочь – AmmarCSE

+0

Мне любопытно: сколько тэгов вы использовали для этих тестов, насколько велика таблица 'Articles' и насколько велика была результирующий набор? – jjj

ответ

3

Использование Except() и Any() как

ApplicationDbContext 
    .Articles 
    .Where(a => tags.Except(a.Tags.Select(t => t.Id).ToList()).Any() == false) 

Except() даст вам элементы из первого списка, который делать не существуют во втором списке

The Кроме оператора создает заданную разницу между двумя последовательностями. Он будет возвращать только элементы в , первые последовательности, которые не отображаются во втором.

+0

Это работает только для статей, которые имеют только совпадающие теги и не более .... право? – br4d

+0

Я не думаю, что это делает то, что хочет OP, поскольку он заявил, что хочет * как минимум * указанных тегов, а не только *. – adam0101

+0

@ br4d, хороший пункт.Ive скорректировал мой ответ – AmmarCSE

1

Итеративное построение результата через IQueryable.

public ActionResult FindAll(List<int> tags) 
{ 
    var queryable = ApplicationDbContext.Articles.AsQueryable(); 

    foreach(var t in tags) 
    { 
     queryable = queryable.Where(w => w.Tags.Any(a => a.Id == t)); 
    } 

    queryable.AsEnumerable(); // stuff this into a viewmodel and return actionresult? 
} 
+0

Спасибо за ваш ответ! В другом комментарии я попытался сделать это как один лайнер. Это возможно с использованием метода Aggregate. tags.Aggregate (ApplicationDbContext.CaseStudies.AsQueryable(), (current, t) => current.Where (w => w.Tags.Any (a => a.Id == t))); – heymega

0

Используйте это:

ApplicationDbContext.Articles.Where(a => tags.All(t => a.Tags.Contains(t))); 
+0

Неправильное использование. Он хочет сопоставить все указанные теги, а не все теги статьи. – adam0101

+0

Обновленный ответ. – ranquild

+0

Это выглядит прямо сейчас, за исключением того, что тег статьи представляет собой объект с свойством Id, а не целое число. – adam0101

2

Это следует сделать это:

ApplicationDbContext.Articles.Where(a => tags.All(t => a.Tags.Any(at => at.Id == t))); 
+0

Я даже не знал, что существует «Все». Ницца! – AmmarCSE

2

Попробуйте это:

var query =from a in ApplicationDbContext.Articles 
      where a.Tags.Count(t => tags.Contains(t.Id)) == tags.Count 
      select a; 
+0

Я думаю, что ваша первая ревизия была правильной. Теперь это соответствует точному количеству тегов, чего не требуется OP. – adam0101

+0

@ adam0101, первый запрос возвратил статьи с хотя бы одним тегом, который соответствует в списке тегов. Теперь, со вторым запросом, я не просто проверяю, что количество тегов одинаково, проверьте условие в подзапросе, если количество содержащихся тегов совпадает с количеством элементов в списке «теги», затем я выбираю статью – octavioccl

+2

'где a.Tags.Count (t => tags.Contains (t.Id)) == tags.Count'? – jjj

1

Как насчет этого?

var articles = ApplicationDbContext.Articles.Where (a => a.Tags.Select (t => t.Id).Intersect(tags).Count()>=tags.Count); 
Смежные вопросы