2009-10-22 8 views
0

Disons que j'ai un modèle de domaine avec une classe appelée Blog qui a une propriété appelée BlogEntries (qui contient des objets de type BlogEntry). Si j'ai un modèle de base de données avec deux tables "Blog" et "BlogEntry", il n'est pas impossible que j'ai 1000 entrées de blog pour un blog. Si je devais montrer le blog sur un site web, je voudrais seulement afficher 20 entrées de blog à la fois, donc je devrais utiliser une sorte de pagination. Je ne veux évidemment pas que 1000 enregistrements soient extraits de la BD tout le temps.Pagination dans NHibernate

Comment est-ce que je ferais cela? La propriété BlogEntries doit-elle être dans l'objet de domaine Blog ou dans le référentiel? Je voudrais toujours avoir la possibilité d'ajouter des entrées de blog ainsi que d'obtenir un résultat paginé de ceux qui existent déjà. À quoi ressemblerait la cartographie de NHibernate? La chose Blog/BlogEntry est juste un exemple, il pourrait tout aussi bien avoir été un exemple client/commande ou tout autre scénario maître/détail.

S'il vous plaît éclairer moi!

Répondre

1

Je voudrais faire de BlogEntry sa propre racine agrégée, avec son propre référentiel. Vous obtiendrez des instances BlogEntry pour un blog particulier en interrogeant le référentiel BlogEntry pour tous les BlogEntry ayant un ID de blog donné. Je ne peux pas fournir de détails sur le dépôt au-delà de cela puisqu'il existe plusieurs stratégies différentes pour implémenter des dépôts (un référentiel générique par rapport à plusieurs, des méthodes de recherche séparées par opposition à un objet de spécification complexe, etc.). La méthode finder du référentiel doit prendre en charge la pagination.

public class Blog 
{ 
    public int ID {get;set;} 
    // other stuff 
} 

public class BlogEntry 
{ 
    public int ID {get;set;} 
    public int BlogID {get;set;} 
} 

public class BlogEntryRepository 
{ 
    public IEnumerable<BlogEntry> FindByBlogID(
     int blogID, int pageIndex, int pageSize) 
    { 
     // implementation 
    } 
} 

Alternativement, (également avec BlogEntry modélisé comme une racine globale), vous pouvez ajouter une collection de BlogEntryIDs à ​​votre classe de blog. Ce serait mieux que d'avoir les instances de BlogEntry elles-mêmes dans la classe Blog car vous auriez beaucoup moins de données à charger lorsque vous voulez obtenir une instance de Blog. Avec ces ID, vous pouvez en sélectionner un sous-ensemble et les transmettre dans une méthode de référentiel BlogEntry qui accepte une collection d'ID. En d'autres termes, il y aurait un peu plus de logique dans votre domaine pour supporter la pagination, et un getter plus générique dans le référentiel.

public class Blog 
{ 
    public int ID {get;set;} 
    public IEnumerable<int> BlogEntryIDs {get;set;} 
    // other stuff 
} 

public class BlogEntry 
{ 
    public int ID {get;set;} 
    public int BlogID {get;set;} 
} 

public class BlogEntryRepository 
{ 
    public IEnumerable<BlogEntry> Get(IEnumerable<int> blogEntryIDs) 
    { 
     // implementation 
    } 
} 

utilisation de cette approche serait comme

// get the second page 
var entries = 
    blogEntryRepo.Get(blog.BlogEntryIDs).Skip(1 * PAGE_SIZE).Take(PAGE_SIZE); 

Dans la base de données, vous retourneraient plusieurs lignes, une pour chaque entrée de blog. (Je préfère également renvoyer plusieurs ensembles de résultats pour obtenir toutes les lignes de toutes les tables liées dans un seul aller-retour de base de données.) J'utilise également la fonction ROW_VERSION de SQL 2005 pour activer la pagination de base de données.)

l'utilisation typique montre des quantités prohibitives de (par exemple plus de deux mille) instances de BlogEntry associées à un Blog. Un tableau de trop d'int me rendrait méfiant des performances et de la mémoire.

+0

J'aime votre réponse, cela a beaucoup de sens. Qu'en est-il de la partie "à moins" - que feriez-vous si le tableau était grand.Lire un millier d'enregistrements à partir d'une base de données sur une autre machine quand vous avez 20 ans semble être une mauvaise idée, du point de vue de la mémoire de performance (comme vous l'avez écrit). – Kristoffer

+0

Dans le cas "sauf", j'irais avec la première approche. J'ai ajouté un exemple de code pour rendre les deux approches plus claires. Dans la deuxième approche, avec la collection de BlogEntryID, même si vous demandez des centaines ou des milliers de lignes, vous ne demandez qu'une seule colonne entière par ligne. La seule façon de voir si cela est acceptable est d'établir des exigences de performance à un certain niveau et d'effectuer des tests préliminaires. Ou allez simplement avec la première approche. –

-1

Pour la collecte des entrées de blog, vous pouvez utiliser l'attribut BatchSize. Il vous permettra de ne pas sélectionner toute la collection de la base de données, seulement les valeurs requises.

+0

Cela va encore charger toutes les valeurs de la première page lors de la navigation vers la page 2 – Paco

1

Vous devez accéder au blogentry dans son propre référentiel pour obtenir une liste de pages.

Modifier: Pourquoi downvote? Est-ce mal?