2012-12-05 3 views
1

Je le modèle suivant:Comment ET prédicats dans la clause WHERE dans un LINQ pour RavenDB requête

public class Clip { 
    public Guid ClipId { get; set; } 
    public IList<StateChange> StateChanges { get; set; } 
} 

public class StateChange { 
    public string OldState { get; set; } 
    public string NewState { get; set; } 
    public DateTime ChangedAt { get; set; } 
} 

Et voilà comment un corbeau de requête:

var now = DateTime.UtcNow; 
var since = now.AddSeconds(60); 
string state = "some state of interest"; 
using (var session = docStore.OpenSession()) { 
      RavenQueryStatistics stats; 
      session.Query<Clip>() 
       .Statistics(out stats) 
       .Where(
        p => p.StateChanges.Any(a => (since > a.ChangedAt && a.NewState == state)) 
        && !p.StateChanges.Any(a => (a.OldState == state && now > a.ChangedAt))) 
       .ToArray(); 
      return stats.TotalResults; 
     } 

Je veux obtenir le comptent pour tous les Clip enregistrements qui ont un (StateChange.CreatedAt avant since et NewState est "some state of interest") et ne pas avoir un (StateChange.CreatedAt avant now et OldState est "some state of interest"). Bien que le prédicat utilisé ci-dessus fonctionne dans linq pour objecter, il ne semble pas fonctionner dans linq à corbeau (c'est-à-dire qu'il ne renvoie pas le résultat attendu). Je soupçonne que c'est parce que l'expression && !.p.StateChanges.Any.... n'est jamais évaluée si l'expression sur le côté gauche évalue à vrai. Y a-t-il un moyen de contourner ce problème?

+0

Que voulez-vous dire par "Ne fonctionne pas"? Y a-t-il une erreur? –

+0

Non, cela signifie qu'il ne renvoie pas les résultats attendus, c'est-à-dire qu'il ignore l'expression de droite –

+0

Comment savez-vous qu'il l'ignore? Si la première condition est vraie, elle doit évaluer la bonne condition pour obtenir le résultat complet de la condition. –

Répondre

3

Ce n'est pas lié à l'évaluation des conditions. & & fonctionne très bien.

Le problème est que RavenDB ne gère pas correctement les requêtes qui utilisent .All (...) ou! .Any (...). Cela est dû à la façon dont le moteur d'index dynamique du corbeau évalue votre instruction linq. Il veut créer une entrée d'index distincte pour chacune de vos entrées StateChange, ce qui ne fonctionnera pas pour les opérations qui doivent prendre en compte plusieurs éléments connexes, tels que les différents changements d'état.

Un problème est déjà enregistré pour ce here. Il a été fermé dans la version 2151 pour renvoyer une exception significative lorsque vous essayez d'interroger de cette manière. Peut-être qu'à une date ultérieure, ils pourront réévaluer s'il existe un moyen d'évaluer réellement ces types de requêtes correctement.

Mise à jour

J'ai pensé à votre défi, et another related one, et a pu trouver une nouvelle technique qui vous permettra de le faire. Il faudra un index statique et requête Lucene:

public class Clips_ByStateChange : AbstractIndexCreationTask<Clip> 
{ 
    public Clips_ByStateChange() 
    { 
    Map = clips => 
      from clip in clips 
      select new { 
       OldState = clip.StateChanges 
        .Select(x => x.OldState + "|" + x.ChangedAt.ToString("o")), 
       NewState = clip.StateChanges 
        .Select(x => x.NewState + "|" + x.ChangedAt.ToString("o")) 
      }; 
    } 
} 

var results = session.Advanced.LuceneQuery<Clip, Clips_ByStateChange>() 
    .Where(string.Format(
     "NewState: {{{0}|* TO {0}|{1}}} AND -OldState: {{{0}|* TO {0}|{2}}}", 
     state, since.ToString("o"), now.ToString("o"))); 

Bien sûr, vous pouvez toujours prendre simplement des statistiques là-dessus si c'est ce que vous voulez.

Questions connexes