2012-01-03 34 views
6

Tôi đang cố gắng để truy vấn Posts dựa trên một danh sách các Tags:LINQ nhiều-nhiều ngã tư

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

Bây giờ tôi muốn quay trở lại bài viết dựa trên một danh sách các thẻ: 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

Khi một bài đăng chứa một hoặc nhiều thẻ cũng tồn tại trong searchTags nó phải được bao gồm trong kết quả. Tôi đã thử những điều sau đây:

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

Lỗi: 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 lỗi: 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. Bất kỳ ý tưởng?

- cập nhật ngày 4 tháng 1: Câu trả lời trỏ đến giải pháp đúng, nhưng trong mã của tôi, tôi vẫn có NotSupportedException. Có thể các số nguyên nullable gây ra điều này vì nó không phải là một kiểu nguyên thủy?

Trả lời

1

Hôm nay tôi gặp phải vấn đề này một lần nữa, và quyết định để giải quyết nó. Vấn đề của câu hỏi của tôi là IList<Tag> searchTags = ParseTagsFromSearchString("tag1,tag2,tag3"); tạo ra một danh sách, điều này sẽ gây ra một ngoại lệ khi được sử dụng trong biểu thức giao nhau của một truy vấn khác trong khung thực thể. Các điều phải làm là thế này:

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

Có thể điều này có thể hoạt động?

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

hoặc có thể

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

Đã không cố gắng bất kỳ này mặc dù, vì vậy không đảm bảo :)

+0

Tôi đã thử các giải pháp thứ hai trong mã LinqPad bưu Đánh dấu Lindel và nó hoạt động.Thật không may, trong mã của tôi tôi nhận được cùng một UnsupportedException .. – Marthijn

1

Cố gắng để chuyển đổi TagList của bạn vào một danh sách các số nguyên Id. Sử dụng điều đó trong truy vấn của bạn để khắc phục NotSupportedException.

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

Sau đó sử dụng tagIds trong truy vấn của bạn ...

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

Tôi không chắc chắn nếu làm tổ Bất kỳ báo cáo như vậy thực sự sẽ làm việc. Chỉ cần giải thích lý do tại sao bạn nhận được ngoại lệ.

3

Bạn sắp thực hiện, chỉ cần thay đổi Intersect(taglist)-Intersect(taglist).Any()

Dưới đây là một ví dụ làm việc (đi cùng định nghĩa của bạn cho 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 

bây giờ, trong mã thực bạn có thể giành chiến thắng Không sử dụng cùng một phiên bản cho các thẻ trong danh sách tìm kiếm và Bài đăng, vì vậy bạn sẽ phải ghi đè Equals và GetHashCode cho Thẻ hoặc cung cấp IEqualityComparer trong lệnh gọi đến Intersect

+0

Cảm ơn câu trả lời của bạn, bây giờ tôi nhận được lỗi này: 'Không thể tạo ra một giá trị không đổi của loại 'Models.Tag'. Chỉ các kiểu nguyên thủy (như Int32, String và Guid ') mới được hỗ trợ trong ngữ cảnh này.' – Marthijn

+0

Tôi đã thêm một mẫu mã hoạt động. Hy vọng nó giúp. Tôi không chắc chắn những gì bạn đang cố gắng đạt được với cuộc gọi Any() lồng nhau trong bản cập nhật của bạn. – voidengine

+0

Tôi đã triển khai IEqualityComparer, nhưng có lỗi này: 'LINQ to Entities không nhận ra phương thức ...'. Như tôi đã nói trong câu hỏi của mình, tôi nghĩ rằng lỗi kiểu nguyên thủy là do 'int?'. Thật không may tôi không thể kiểm tra nó trong ứng dụng của tôi bởi vì một số mã đã được sản xuất. – Marthijn

0

Ném này với nhau trong 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

Cảm ơn, trong LinqPad công trình này thực sự (btw công cụ tốt đẹp), nhưng trong mã của tôi tôi nhận được 'Không thể tạo ra một giá trị không đổi của loại 'Models.Tag'. Chỉ các kiểu nguyên thủy (như Int32, String và Guid ') được hỗ trợ trong ngữ cảnh này.' Rất lạ vì mã này và mã của tôi ít nhiều giống nhau. – Marthijn

Các vấn đề liên quan