2012-01-03 56 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