2010-09-10 6 views
0

J'ai 4 tables de base de données (canal, utilisateur, message, User2Channel) et selon les classes entité:NHibernate beaucoup à plusieurs et SELECT N + 1 problème

class **Channel** { 
int ChannelId {get;set;} 
int ISet<User> UsersToChannel {get;set;} 
... 
} 
class **Message** { 
int MessageId {get;set;} 
Channel Channel {get;set;} 
User User {get;set;} 
... 
} 
class **User**{ 
int UserId {get;set;} 
ISet<Channel> Channels {get;set;} 
... 
} 

J'utilise fluentnhibernate pour la cartographie:

class **ChannelMap** { 
    ChannelMap(){ 
     ... 
     HasManyToMany(x => x.UsersInChannel) 
       .AsSet() 
       .Cascade.All().Inverse() 
       .Table("User2Channel") 
       .Not.LazyLoad(); 
    } 
} 
class **UserMap** { 
    UserMap(){ 
     HasManyToMany(x => x.Channels) 
       .AsSet() 
       .Cascade.All() 
       .Table("User2Channel") 
       .Not.LazyLoad(); 
    } 
} 

je charger des messages dans ce code:

... 
var query = session.CreateQuery(@"select m from Message m"); 
var msgs = query.List<Message>(); 
... 

à profileur Je vois beaucoup de questions comme celle-ci:

SELECT ... FROM User2Channel WHERE ChannelId=654 
SELECT ... FROM User2Channel WHERE ChannelId=655 
etc 

S'il vous plaît! Aidez moi! Comment je peux résoudre ce problème? Si j'ai plusieurs milliers de canaux - j'obtiens aussi beaucoup de requêtes dans la base de données!

Répondre

2

Vous pouvez les charger en utilisant des lots. C'est l'option la moins intrusive (signifie: vous n'avez rien à faire dans votre code de domaine).

Je ne sais pas couramment. Ceci est le mappage xml dont vous avez besoin:

<set name="Channels" ... batch-size="50"> 
    ... 
</set> 

Ceci permet à NH de pré-charger 50 canaux à la fois. Il leur requête comme ceci:

SELECT ... FROM User2Channel WHERE ChannelId IN (654, 655, 656, ... 704) 

Cela rend le N+1 un N/50+1.

+0

Stefan a raison. En outre, les requêtes multiples lors de l'exécution de la requête sont causées par 'Not.LazyLoad' que vous avez ajouté. –

+0

Merci pour ce commentaire Diego. Avait une requête linq qui présentait une instruction Fetch et avait également Not.LazyLoad spécifié dans le mappage - ce qui provoquait l'appel de 2 requêtes. Supprimé le Not.LazyLoad dans le mapping et tout est génial. – Chev