2010-11-17 28 views
17

Tôi có một lớp tài liệu chứa danh sách "thẻ". Một cái gì đó như:Truy vấn LINQ với nhiều Chứa/Bất kỳ cho RavenDB

class Item { 
    string Name { get; set; } 
    List<string> Tags {get; set;} 
} 

Bây giờ tôi muốn tạo một truy vấn cho RavenDB đưa cho tôi tất cả các mục được lọc theo danh sách các thẻ. Khi sử dụng Entity Framework tôi quản lý để làm điều này bằng một cái gì đó như thế này:

var query = GetQueryable(); 
foreach (var tag in tags) 
{ 
    query = query.Where(i => i.Tags.Contains(tag)); 
} 

Tuy nhiên, điều này dường như không làm việc với RavenDB, rất có thể vì Có không được hỗ trợ .. Tôi cũng đã cố gắng viết lại nó sử dụng Bất kỳ, (Where(i => i.Tags.Any(t=>t == tag))) nhưng điều đó mang lại cho tôi một ngoại lệ lạ:

Unable to cast object of type 
'System.Linq.Expressions.PrimitiveParameterExpression`1[System.String]' 
to type 'System.Linq.Expressions.MemberExpression 

Bất kỳ ý tưởng tuyệt vời nào? Tôi làm điều này hoàn toàn sai?

+0

Loại trả về 'GetQueryable()' là gì? và bạn đang làm gì trong 'query = query.Where (i => i.Tags.Contains (tag));'? loại truy vấn là gì? –

+0

GetQueryable() trả về một IQueryable . Tôi có quyền truy cập vào toàn bộ DocumentSession mặc dù, vì vậy đó chỉ là một ví dụ. – CodingInsomnia

Trả lời

18

Có thực sự là chưa được hỗ trợ (Có lẽ nó nên được, nhưng đó là một vấn đề khác hoàn toàn - chúng tôi chỉ thực sự hỗ trợ thêm cho các nhà khai thác khác nhau khi được hỏi nó cho)

Đối với nhiều truy vấn đối với Bất kỳ, tôi giả sử bạn' tái cố gắng để làm dữ liệu động và bạn muốn đạt được cái gì đó như

"X OR Y OR Z" 

Đó là một khó khăn, và các nhà cung cấp LINQ theo mặc định sẽ tổng hợp những nhiều mệnh đề WHERE với AND, nên ví dụ của bạn trông giống như

"X AND Y AND Z" 

Điều này rõ ràng sẽ không bao giờ xảy ra.

lựa chọn tốt nhất của bạn cho một này là để thả xuống để truy vấn Lucene (ít nhất là cho bây giờ) và làm một cái gì đó như thế này:

var results = s.Advanced.LuceneQuery<Item>() 
        .Where(string.Format("Tags,:({0})", string.Join(" OR ", tags))); 

Make ý nghĩa?

Các truy vấn trên sẽ giống như thế

"Tags,:(X OR Y OR Z)" 

Lưu ý: "Thẻ," RavenDB thông báo rằng Thẻ là một mảng

Okay, [sửa]!

Cách dễ nhất để có được những gì bạn thực sự muốn là để làm một cái gì đó dọc theo những dòng

   new IndexDefinition<Item, Item>() 
       { 
        Map = docs => from doc in docs 
            select new 
            { 
             Tags = doc.Tags 
            }, 
        Indexes = {{ x => x.Tags, FieldIndexing.Analyzed }} 
       }.ToIndexDefinition(store.Conventions)); 

Sau đó, để truy vấn cho ands, bạn có thể làm điều gì đó như thế này:

   var results = s.Advanced.LuceneQuery<Item, WhateverYouCalledThatIndex>() 
        .Where(string.Format("Tags:({0})", string.Join(" AND ", tags))); 

Bây giờ, những điều cần lưu ý về

 Tags = doc.Tags 

Wi sẽ tuần tự hóa toàn bộ mảng đó thành một đốm màu khổng lồ, vì nó chỉ là các chuỗi sẽ hoạt động cho ví dụ này.

Tôi đang tìm cách tốt hơn để thể hiện điều này, không chắc chúng tôi sẽ tìm ra cách làm LINQ-ish, vì nó không thực sự được vẽ trên rất tốt - nhưng nó là Câu trả lời sẽ làm việc :)

tôi nghĩ tôi khá muốn để có thể ít nhất là làm

Map = docs => from doc in docs 
            select new 
            { 
             Tags = String.Join(" ", doc.Tags) 
            }, 

(Điều này sẽ không làm việc vì vậy đừng thử nó), nhưng nó là một chút rõ ràng hơn về những gì bạn muốn đạt được.

+0

Đóng, nhưng không có xì gà! ;-) Trước hết, phiên bản tôi sử dụng dường như không hoạt động với cú pháp "Thẻ ,:". Tuy nhiên, nếu tôi tạo một lớp Thẻ với một thuộc tính duy nhất có tên là Tên (và sử dụng "Thẻ, Tên:"), thì giải pháp của bạn sẽ hoạt động. Nhưng nó không làm chính xác những gì tôi cần. Tôi chỉ muốn trả lại những mục có TẤT CẢ các thẻ trong danh sách thẻ (không phải bất kỳ thẻ nào). – CodingInsomnia

+0

Được rồi, R isNG khó hơn, bạn sẽ làm như thế nào với tư cách là một hoạt động dựa trên bộ trong cơ sở dữ liệu quan hệ? Tôi nghĩ vào thời điểm này, bạn có thể phải tạo một chỉ mục để hợp nhất các thẻ đó vào một trường đơn và chỉ định trình phân tích bạn muốn và sử dụng truy vấn Lucene để nói "Tất cả các điều khoản này" " –

+0

Vâng, nó không đẹp lắm trong một DB quan hệ, nhưng mã tôi đã viết trong câu hỏi thực sự làm việc với Entity Framework. Không đẹp lắm, và hầu như không hiệu quả lắm (đó là một phần lý do tôi nghĩ rằng có lẽ Raven sẽ có thể làm tốt hơn). – CodingInsomnia

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