Question

Je cherche un moyen de récupérer le "& entourer" " lignes dans une requête NHibernate étant donné une clé primaire et un ordre de tri?

E.g. J'ai une table avec des entrées de 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 ordonnées par date (il n'y a pas de relation directe entre la date et la clé primaire). Une telle requête doit renvoyer 11 lignes au total (tant que nous ne sommes pas proches de l'une ou l'autre des extrémités).

Le tableau des entrées de journal peut être énorme et il est impossible de tout récupérer pour le comprendre.

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.

Modifié , exemple ajouté

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 la clé primaire 4242, vous devez obtenir les lignes 1237, 1238 et 4239 à 4247. La commande est par heure, id.

Est-il possible de récupérer les entrées dans une seule requête (qui peut évidemment inclure des sous-requêtes)? Le temps étant une colonne non unique, plusieurs entrées ont la même valeur. Dans cet exemple, il est impossible de modifier la résolution de manière à la rendre unique!

Était-ce utile?

La solution

"Il n’existe aucune relation directe entre la date et la clé primaire " signifie que les clés primaires ne sont pas dans un ordre séquentiel?

Ensuite, je le ferais comme ceci:

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);

Autres conseils

Cela devrait être relativement facile avec l’API 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>();

Votre listOfIds est simplement une liste d'entiers fortement typée représentant les identifiants des entrées à récupérer (entiers 4242-5 à 4242 + 5).

Bien sûr, vous pouvez également ajouter des expressions permettant de récupérer des identifiants supérieurs à 4242-5 et inférieurs à 4242 + 5.

La solution de Stefan fonctionne définitivement, mais il existe une meilleure solution en utilisant une seule sous-requête sélectionnée et imbriquée:

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>();

Il s'agit de la syntaxe NHibernate 2.0, mais il en va de même pour les versions antérieures où vous utilisez plutôt l'expression Restrictions.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top