2010-09-10 72 views
0

我有4个数据库表(频道,用户,消息,User2Channel),并根据实体类:NHibernate的许多一对多和SELECT N + 1问题

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;} 
... 
} 

我使用fluentnhibernate映射:

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

我在此代码加载消息:

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

在探查我看到许多疑问是这样的:

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

请!帮我!我如何解决这个问题?如果我拥有数千个频道 - 我也会收到很多数据库查询!

回答

2

您可以使用批量加载它们。这是一个不太干扰的选项(意思是说:你不需要在你的域代码中做任何事情)。

我不知道流利。因此,这是您需要的xml映射:

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

这可以让NH一次预取50个通道。它会询问他们是这样的:

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

这使得N+1一个N/50+1

+0

斯蒂芬是对的。另外,执行查询时的多个查询由您添加的'Not.LazyLoad'引起。 – 2010-09-12 17:31:11

+0

感谢评论迭戈。如果linq查询具有Fetch语句并且映射中指定了Not.LazyLoad,则会导致调用2个查询。删除了映射中的Not.LazyLoad,并且都很棒。 – Chev 2011-04-16 10:16:42