سؤال
لدي فئة مستندات تحتوي على قائمة "العلامات". شيء مثل:
class Item {
string Name { get; set; }
List<string> Tags {get; set;}
}
الآن أود إنشاء استعلام لـ Ravendb يمسحني جميع العناصر التي تمت ترشيحها بقائمة من العلامات. عند استخدام إطار الكيان ، تمكنت من القيام بذلك بشيء من هذا القبيل:
var query = GetQueryable();
foreach (var tag in tags)
{
query = query.Where(i => i.Tags.Contains(tag));
}
ومع ذلك ، لا يبدو أن هذا يعمل مع RavendB ، على الأرجح لأنه لا يوجد مدعوم .. لقد حاولت أيضًا إعادة كتابته باستخدام أي ، (Where(i => i.Tags.Any(t=>t == tag))
) لكن هذا يعطيني استثناء غريب:
Unable to cast object of type
'System.Linq.Expressions.PrimitiveParameterExpression`1[System.String]'
to type 'System.Linq.Expressions.MemberExpression
أي أفكار عظيمة؟ هل أفعل هذا خطأً تمامًا؟
المحلول
لا يتم دعمه في الواقع (ربما ينبغي أن يكون كذلك ، لكن هذه مسألة أخرى تمامًا - نضيف حقًا دعمًا لمختلف المشغلين عند طلبها)
أما بالنسبة للاستعلامات المتعددة ضد أي ، أفترض أنك تحاول القيام ببيانات ديناميكية وتريد تحقيق شيء مثل
"X OR Y OR Z"
هذا أمر صعب ، وسيقوم مزود LINQ بشكل افتراضي بتجميع تلك المتعددة حيث الجمل مع ، وبالتالي يبدو مثالك
"X AND Y AND Z"
من الواضح أنه لن يكون الأمر كذلك.
خيارك الأفضل لهذا الشخص هو النزول إلى استعلام Lucene (على الأقل في الوقت الحالي) والقيام بشيء مثل هذا:
var results = s.Advanced.LuceneQuery<Item>()
.Where(string.Format("Tags,:({0})", string.Join(" OR ", tags)));
منطقي؟
سيبدو الاستعلام أعلاه شيئًا مثل
"Tags,:(X OR Y OR Z)"
ملاحظة: "العلامات" ، تقوم بإبلاغ Ravendb بأن العلامات عبارة عن صفيف
حسنًا ، [تحرير]!
أسهل طريقة للحصول على ما أنت بالفعل تريد هو القيام بشيء على هذا النحو
new IndexDefinition<Item, Item>()
{
Map = docs => from doc in docs
select new
{
Tags = doc.Tags
},
Indexes = {{ x => x.Tags, FieldIndexing.Analyzed }}
}.ToIndexDefinition(store.Conventions));
ثم للاستعلام عنك ، يمكنك أن تفعل شيئًا كهذا:
var results = s.Advanced.LuceneQuery<Item, WhateverYouCalledThatIndex>()
.Where(string.Format("Tags:({0})", string.Join(" AND ", tags)));
الآن ، أشياء يجب أن تكون على دراية بها
Tags = doc.Tags
سوف يقوم بتسلسل هذا الصفيف بأكمله إلى نقطة عملاقة واحدة ، حيث إنها مجرد سلاسل ستعمل على هذا المثال.
أنا أتطلع إلى طرق أفضل للتعبير عن ذلك ، فمن غير المرجح أن نتوصل إلى طريقة LINQ -ish للقيام بذلك ، لأنها لا تخطط جيدًا حقًا - ولكنها هو إجابة ستعمل :)
أعتقد أنني أود أن أكون قادرًا على الأقل على القيام به
Map = docs => from doc in docs
select new
{
Tags = String.Join(" ", doc.Tags)
},
(هذا لن ينجح ، لذلك لا تجربه) ، لكنه أكثر وضوحًا حول ما تريد تحقيقه.