2012-01-03 63 views
6

我试图根据的Tags名单上查询PostsLINQ许多一对多路口

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。它可能是可空的整数,因为它不是原始类型?

回答

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(); 
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; 

没有尝试过任何这虽然,所以不能保证:)

+0

我已经尝试了Mark Lindel的帖子LinqPad代码中的第二个解决方案,它的工作原理。不幸的是,在我的代码中,我得到了相同的UnsupportedException .. – Marthijn 2012-01-04 07:50:15

1

尝试将您的标记列表转换为整数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; 

我不知道,如果像嵌套的任何语句将实际工作。只是解释你为什么会得到例外。

3

你几乎没有,只是改变Intersect(taglist)Intersect(taglist).Any()

这里有一个工作示例(以及您的定义去为PostTag):

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 

现在,在真正的代码,你可能赢不会在搜索列表和帖子中使用相同的标签实例,因此您必须覆盖标签的等于和GetHashCode,或在调用Intersect时提供IEqualityComparer

+0

感谢您的回答,现在我得到了这个错误:'无法创建类型'Models.Tag'的常量值。只有原始类型('Int32,String和Guid')在此上下文中受支持。' – Marthijn 2012-01-04 07:33:20

+0

我已经添加了一个工作代码示例。希望能帮助到你。我不确定你想用更新中的嵌套Any()调用来实现什么。 – voidengine 2012-01-04 14:27:05

+0

我实现了一个IEqualityComparer,但遇到了这个错误:'LINQ to Entities does not recognized the method ...'。正如我在我的问题中所说的,我认为原始类型错误是由'int?'引起的。不幸的是,我无法在我的应用中测试它,因为一些代码已经在生产中。 – Marthijn 2012-01-04 15:05:22

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;} 
} 
+0

谢谢,在LinqPad这工作确实(很好的工具btw),但在我的代码中,我得到'无法创建一个'Models.Tag'类型的常量值。这种情况下只支持原始类型(如Int32,String和Guid)。“由于这段代码和我的代码差不多,所以很奇怪。 – Marthijn 2012-01-04 07:37:08