LINQ перекресток многие ко многим - PullRequest
6 голосов
/ 03 января 2012

Я пытаюсь запросить Posts на основе списка Tags:

public class Post
{
  public int? Id {get;set;}
  public string Name {get;set;}
  public virtual ICollection<Tag> Tags {get;set;}
}
public class Tag
{
  public int? Id {get;set;}
  public string Name {get;set;}
  public vritual ICollection<Post> Posts {get;set;}
}

Теперь я хочу возвращать сообщения на основе списка тегов: IList<Tag> searchTags = ParseTagsFromSearchString("tag1,tag2,tag3"); // this function checks the tags in the database, so all the primary keys are available in the list

Если сообщение содержит один или несколько тегов, которые также существуют в searchTags, оно должно быть включено в результат.Я пробовал следующее:

var q = from s in Context.Registrations
                    where s.Tags.Intersect(tagList)
                    select s;

Ошибка: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<Models.Tag>' to 'bool'

var q = from s in Context.Registrations
                    where s.Tags.Any(t => tagList.Any(t2 => t.Id.Value == t2.Id.Value))
                    select s;

Ошибка выполнения: NotSupportedException: Unable to create a constant value of type 'Models.Tag'. Only primitive types ('such as Int32, String, and Guid') are supported in this context. Есть идеи?

- обновление 4 января.Ответы указывают на правильное решение, но в моем коде у меня все еще есть исключение NotSupportedException.Возможно ли, что обнуляемое целое число вызывает это, так как это не примитивный тип?

Ответы [ 5 ]

3 голосов
/ 03 января 2012

Вы почти у цели, просто измените Intersect(taglist) на Intersect(taglist).Any()

Вот рабочий пример (следуя вашим определениям для Post и Tag):

Tag tag1 = new Tag() { Id = 1, Name = "tag1" };
Tag tag2 = new Tag() { Id = 2, Name = "tag2" };
Tag tag3 = new Tag() { Id = 3, Name = "tag3" };

List<Post> posts = new List<Post>() {
    new Post() { Id = 1, Name = "post1", Tags = new Tag[] {tag1} },
    new Post() { Id = 2, Name = "post2", Tags = new Tag[] {tag2} },
    new Post() { Id = 3, Name = "post3", Tags = new Tag[] {tag3} },
    new Post() { Id = 4, Name = "post13", Tags = new Tag[] {tag1, tag3} },
};

List<Tag> searchTags = new List<Tag>() { tag1, tag2 };

IEnumerable<Post> matching = posts.Where(p => p.Tags.Intersect(searchTags).Any());
//matching now contains post1, post2 and post13

теперь в реальном коде вы, вероятно, не будете использовать одни и те же экземпляры для тегов в списке поиска и в сообщениях, поэтому вам придется переопределить Equals и GetHashCode для тега или предоставить IEqualityComparer при вызове Intersect

1 голос
/ 25 октября 2012

Сегодня я снова столкнулся с этой проблемой и решил ее решить. Проблема моего вопроса заключается в том, что IList<Tag> searchTags = ParseTagsFromSearchString("tag1,tag2,tag3"); создает список, который вызовет исключение при использовании в выражении пересечения другого запроса в структуре сущностей. Вот что нужно сделать:

var q = ParseTagsFromSearchString("tag1,tag2,tag3"); // this function will now build a query instead of a list
IList<Post> posts = (from s in Context.Posts where s.Tags.Intersect(q.AsEnumerable()).Any() select s).ToList();
1 голос
/ 03 января 2012

Попробуйте преобразовать свой TagList в список целочисленных идентификаторов.Используйте это в своем запросе, чтобы исправить NotSupportedException.

var tagIds = tagList.Select(x=>x.Id);

Затем используйте теги ID в своем запросе ...

var q = from s in Context.Registrations
                    where s.Tags.Any(t => tagIds.Any(t2 => t.Id.Value == t2.Id))
                    select s;

Я не уверен, что вложение Любые подобные утверждения действительно будут работатьПросто объясняю, почему вы получили исключение.

0 голосов
/ 03 января 2012

Скинул это вместе в LinqPad :

void Main()
{
   var tag1 = new Tag { Name = "tag1" };
   var tag2 = new Tag { Name = "tag2" };
   var tag3 = new Tag { Name = "tag3" };

    var posts = new List<Post>
    {   
        new Post 
        {
            Name = "Post1",
            Tags = new List<Tag> { tag1, tag3 }
        },
        new Post 
        {
            Name = "Post2",
            Tags = new List<Tag> { tag2, tag3 }
        }
    };

    var tagList = new List<Tag> { tag1 };

    var q = posts.Where(x => x.Tags.Intersect(tagList).Any());

    q.Dump();
}

public class Post 
{ 
  public int? Id {get;set;} 
  public string Name {get;set;} 
  public virtual ICollection<Tag> Tags {get;set;} 
} 

public class Tag 
{ 
  public int? Id {get;set;} 
  public string Name {get;set;} 
  public virtual ICollection<Post> Posts {get;set;} 
} 
0 голосов
/ 03 января 2012

Может быть, это может сработать?

var q = from s in Context.Registrations
                    where s.Tags.Intersect(tagList).Count() != 0
                    select s;

или, может быть,

var q = from s in Context.Registrations
                    where s.Tags.Any(t => tagList.Contains(t))
                    select s;

Хотя не пробовал ничего из этого, так что никаких гарантий:)

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