我正在尝试根据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.
有什么想法吗?
- 1月4日更新: 答案指向正确的解决方案,但在我的代码中我仍然有NotSupportedException。可以为空的整数是否可能导致这种情况,因为它不是原始类型?
答案 0 :(得分:3)
你几乎就在那里,只需将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,或者在调用Intersect时提供IEqualityComparer
答案 1 :(得分:1)
尝试将TagList转换为整数ID列表。在查询中使用它来修复NotSupportedException。
var tagIds = tagList.Select(x=>x.Id);
然后在查询中使用tagIds ...
var q = from s in Context.Registrations
where s.Tags.Any(t => tagIds.Any(t2 => t.Id.Value == t2.Id))
select s;
我不确定是否嵌套这样的任何语句都会有效。只是解释你为什么得到例外。
答案 2 :(得分:1)
今天我又遇到了这个问题,并决定解决它。我的问题是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();
答案 3 :(得分:0)
也许这可行吗?
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;
虽然没有尝试过,所以不保证:)
答案 4 :(得分:0)
在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;}
}