2009-05-08 10 views
0

Je cherche un moyen de récupérer les lignes "environnantes" dans une requête NHibernate avec une clé primaire et un ordre de tri?Récupère les lignes "environnantes" dans la requête NHibernate

E.g. J'ai une table avec les entrées du journal et je veux afficher l'entrée avec la clé primaire 4242 et les 5 entrées précédentes ainsi que les 5 entrées suivantes classées par date (il n'y a pas de relation directe entre la date et la clé primaire). Une telle requête devrait renvoyer 11 lignes au total (tant que nous ne sommes pas proches de l'une ou l'autre fin).

La table d'entrée de journal peut être très volumineuse et il n'est pas possible de tout extraire pour la déterminer.

Existe-t-il un concept tel que le numéro de ligne pouvant être utilisé depuis NHibernate? La base de données sous-jacente sera SQlite ou Microsoft SQL Server.

Edité Ajouté échantillon

Imaginez des données telles que les suivantes:

Id Time 
4237 10:00 
4238 10:00 
1236 10:01 
1237 10:01 
1238 10:02 
4239 10:03 
4240 10:04 
4241 10:04 
4242 10:04 <-- requested "center" row 
4243 10:04 
4244 10:05 
4245 10:06 
4246 10:07 
4247 10:08 

Lorsque vous demandez l'entrée avec 4242 clé primaire, nous devrions obtenir les lignes 1237, 1238 et 4239 à 4247. L'ordre est par Time, Id.

Est-il possible de récupérer les entrées dans une seule requête (qui peut évidemment inclure des sous-requêtes)? Time est une colonne non unique, donc plusieurs entrées ont la même valeur et dans cet exemple il n'est pas possible de changer la résolution d'une manière qui la rend unique!

Répondre

1

"il n'y a pas de relation directe entre la date et la clé primaire" signifie que les clés primaires ne sont pas dans un ordre séquentiel?

Alors je fais comme ça:

Item middleItem = Session.Get(id); 

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item)) 
    .Add(Expression.Le("Time", middleItem.Time)) 
    .AddOrder(Order.Desc("Time")) 
    .SetMaxResults(5); 

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item)) 
    .Add(Expression.Gt("Time", middleItem.Time)) 
    .AddOrder(Order.Asc("Time")) 
    .SetMaxResults(5); 

Il y a le risque d'avoir plusieurs éléments avec le même temps.


Modifier

Cela devrait fonctionner maintenant.

Item middleItem = Session.Get(id); 

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item)) 
    .Add(Expression.Le("Time", middleItem.Time)) // less or equal 
    .Add(Expression.Not(Expression.IdEq(middleItem.id))) // but not the middle 
    .AddOrder(Order.Desc("Time")) 
    .SetMaxResults(5); 

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item)) 
    .Add(Expression.Gt("Time", middleItem.Time)) // greater 
    .AddOrder(Order.Asc("Time")) 
    .SetMaxResults(5); 
+0

Je suppose que cela fonctionnera aussi longtemps que la commande est sur une colonne qui contient des valeurs uniques. Je pourrais avoir besoin de trier sur différentes colonnes, donc garder une colonne de séquence ne fonctionnera pas. Je cherchais une solution de rownum pour les situations où j'avais besoin de trier des colonnes non-uniques donc plus d'idées sont plus que bienvenues :-) – HakonB

+0

Ok, raffiné. Voir la nouvelle section. –

0

Cela devrait être relativement facile avec l'API de critères de NHibernate:

List<LogEntry> logEntries = session.CreateCriteria(typeof(LogEntry)) 
.Add(Expression.InG<int>(Projections.Property("Id"), listOfIds)) 
.AddOrder(Order.Desc("EntryDate")) 
.List<LogEntry>(); 

Voici votre listOfIds est juste une liste fortement typée de nombres entiers représentant les IDs des entrées que vous souhaitez récupérer (entiers 4242-5 à 4242 + 5).

Bien sûr, vous pouvez également ajouter Expressions qui vous permet de récupérer des ID supérieurs à 4242-5 et inférieurs à 4242 + 5.

+1

Comment vais-je jamais avoir de la réputation? :) Quand j'ai posté une réponse dans les 5 minutes quelqu'un d'autre avait posté un aussi. –

+0

C'est comme avec de l'argent. Si vous l'avez, vous l'obtenez. Les gens votent plus souvent pour les réponses des membres de haute réputation. La vie n'est pas juste. Mais s'en fout, fournir de bonnes réponses est toujours apprécié et devrait être l'intention principale. –

+0

Comme Stefan l'a noté ci-dessus, il n'y a pas de relation directe entre la date et la clé primaire, donc la sélection par clé primaire ne fonctionnera pas. Je pourrais avoir une solution où j'ai également besoin de filtrer par catégorie qui invalide la solution de clé primaire. – HakonB

0

solution de Stefan fonctionne vraiment, mais de meilleure façon existe en utilisant un seul sous-requêtes imbriquées et sélectionnez:

ICriteria crit = NHibernateSession.CreateCriteria(typeof(Item)); 

     DetachedCriteria dcMiddleTime = 
      DetachedCriteria.For(typeof(Item)).SetProjection(Property.ForName("Time")) 
      .Add(Restrictions.Eq("Id", id)); 

     DetachedCriteria dcAfterTime = 
      DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id")) 
      .Add(Subqueries.PropertyGt("Time", dcMiddleTime)); 
     DetachedCriteria dcBeforeTime = 
      DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id")) 
       .Add(Subqueries.PropertyLt("Time", dcMiddleTime)); 

     crit.AddOrder(Order.Asc("Time")); 
     crit.Add(Restrictions.Eq("Id", id) || Subqueries.PropertyIn("Id", dcAfterTime) || 
       Subqueries.PropertyIn("Id", dcBeforeTime)); 

     return crit.List<Item>(); 

Cette syntaxe est NHibernate 2.0, mais en est de même pour les versions antérieures à la place où des restrictions que vous utilisez l'expression.

J'ai testé sur une application de test et il fonctionne comme annoncé

+0

Cela fonctionne très bien tant que le temps est unique mais il échoue lorsque le temps "intermédiaire" est partagé entre plusieurs lignes en raison des restrictions PropertyGt/Lt. Cependant, le passage à PropertyGe/Le ne fonctionne pas non plus. Essayez d'utiliser les valeurs de temps de ma question dans votre échantillon et voyez ce que je veux dire. Btw, votre code m'a certainement appris quelque chose de nouveau à propos des sous-requêtes :-) – HakonB

+0

bleh, la cécité temporaire m'a fait manquer l'exigence non-unique. puisqu'il n'y a pas d'ordre séquentiel dans l'ensemble de données, je ne vois aucun moyen de fournir la réponse requise – Jaguar

Questions connexes