2014-01-30 1 views
0

У меня возникли проблемы с запросом базы данных MongoDB с использованием динамического генерации предиката.MongoDB with C# - запрос с динамически сгенерированным предикатом

документ structue я пытаюсь запросить на это:

{ 
    "_id" : 3121 , 
    "Active" : true , 
    "CategoryId" : 1 , 
    "Crci" : "IH" , 
    "CultureId" : null , 
    "DateUpdated" : { 
      "$date" : 1381916923120 
    } , 
    "Description" : "National Careers Service: Actuary" , 
    "Keywords" : "" , 
    "MaxLevel" : null , 
    "MinLevel" : null , 
    "PhoneNumber" : "     " , 
    "Priority" : 1 , 
    "Title" : "National Careers Service: Actuary" , 
    "WebUrl" : "https://nationalcareersservice.direct.gov.uk/advice/planning/jobprofiles/Pages/actuary.aspx" , 
    "CareerCultureExternalResources" : [ 
     { 
       "CareerId" : 5 , 
       "CultureId" : 1 , 
       "DisplayOrder" : 1 , 
       "ExternalResourceId" : 3121 , 
       "Vgs" : null 
     } 
    ] , 
    "SubjectExternalResources" : [ ] , 
    "LifestyleCategories" : null 
} 

И я пытаюсь запросить, используя в предикат, который генерируется во время выполнения, например:

Expression<Func<ExternalResourceView, bool>> predicate = predicateBuilder.True<ExternalResourceView>(); 
if (request.CultureId != null && request.CareerId != null) { 
    predicate = predicate.And(er => er.CareerCultureExternalResources.Any(ccer => ccer.CareerId == request.CareerId.Value && ccer.CultureId == request.CultureId.Value)); 
} 
else if (request.SubjectAreaId != null && request.SubjectLevel != null && request.CultureId != null) 
{ 
    predicate = predicate.And(er => er.SubjectExternalResources.Any(ser => ser.SubjectAreaId == request.CareerId && ser.CultureId == request.CultureId)); 
} 
IEnumerable<ExternalResourceView> matchingExternalResources = _externalResourceLibrary.AsQueryable().Where(predicate) 

Когда я пытаюсь выполнить запрос я получаю ошибку: «Unsupported where clause: <InvocationExpression>».

Я не могу найти, может ли Linq to Mongo генерировать запрос из такого выражения или нет (я думаю, он должен).

Так что я просто пытаюсь сделать что-то, что драйвер C# Mongo не поддерживает, или я не создаю предикат? Я видел от another question, что то, что я пытаюсь сделать, должно быть возможно (теоретически, по крайней мере).

Я использую официальный драйвер 10gen версии 1.8.3

+0

вы можете попробовать .Tolist() независимо от .AsQueryable() –

+0

@ RaphaëlAlthaus Я совсем забыл про AsExpandable (!) И это решило проблему. Если вы добавите это как ответ, я соглашусь с ним. – Anduril

ответ

4

Не уверен, что это решение для mongodb, но можете ли вы попытаться использовать AsExpandable(), исходящий из linqkit (сделанный тем же парнем, что и PredicateBuilder).

LinqKit (и более подробную информацию о AsExpandable() и отношения с PredicateBuilder) можно найти here

+1

Я могу подтвердить, что он работает для MongoDb. Если у вас есть предикат в форме 'Expression > предикат;' Тогда вы можете запросить коллекцию mongo в C# с помощью 'collection.AsQueryable () .AsExpandable(). Где (предикат);' – Anduril

1

Используйте конструктор MongoDB запросов вместо перевода предикат дважды:

using MongoDB.Driver.Builders; 
List<IMongoQuery> queries = new List<IMongoQuery>(); 
if (request.CultureId != null && request.CareerId != null) { 
    queries.Add(
    Query<Person>.ElemMatch<IDependent>(p => p.Dependents, 
     q => Query.And(
     q.EQ(x => x.CareerId, request.CareerId), 
     q.EQ(x => x.CultureId, request.CultureId)))); 
} 
// ... etc 
// Final Query: 
var query = Query.And(queries); 

Я изменил запрос использовать $elemMatch, потому что у меня есть чувство, которое вы хотите сопоставить как careerId, так и cultureId на том же элементе массива. Если это предположение неверно, соответствующим образом настройте запрос.

+0

Спасибо, вы правы, что мы делаем дополнительную работу, существенно переведя предикат дважды, но мы хотим придерживаться linq, а не связывать наши запросы с mongo, если мы хотим переключатель в будущем – Anduril