I'm trying to query Posts
based on a list of 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;}
}
Now I want to return posts based a list of tags:
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
When a post contains one or more tags that also exists in searchTags
it should be included in the result. I have tried the following:
var q = from s in Context.Registrations
where s.Tags.Intersect(tagList)
select s;
Error: 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;
Runtime error: 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.
Any ideas?
-- update Jan. 4: The answers point to the right solution, but in my code I still have the NotSupportedException. Is it possible the nullable integer causes this since it is not a primitive type?
You're almost there, just change the Intersect(taglist)
to Intersect(taglist).Any()
Here's a working example (going along your definitions for Post
and 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
now, in real code you probably won't use the same instances for tags in the search list and the Posts, so you'll have to override Equals and GetHashCode for Tag or provide an IEqualityComparer in the call to Intersect
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With