我目前正在编写一个访问遗留数据库的应用程序。我使用nhibernate作为我的ORM。
数据库中有三个表,它们代表一个(几乎)经典的多对多关系。不同的是,链接表还包含额外的数据。
代码看起来像这样:
public class User
{
public virtual string Login { get; set;}
public virtual string Name { get; set;}
public virtual IList<UserRole> UserRoles { get; set;}
}
public class Role
{
public virtual int Id { get; set;}
public virtual string Description { get; set;}
public virtual IList<UserRole> UserRoles { get; set;}
}
public class UserRole
{
public virtual User User { get; set;}
public virtual Role Role { get; set;}
public virtual bool Active { get; set;}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("Users");
Id(u => u.Login).Column("USER_LOGIN").GeneratedBy.Assigned();
Map(u => u.Name).Column("USER_NAME");
HasMany(u => u.UserRoles).KeyColumn("USER_LOGIN");
}
}
public class RoleMap : ClassMap<Role>
{
public RoleMap()
{
Table("Roles");
Id(r => r.Id).Column("ROLE_ID").GeneratedBy.Assigned();
Map(r => r.Description).Column("ROLE_DESCR");
HasMany(r => r.UserRoles).KeyColumn("ROLE_ID");
}
}
public class UserRoleMap : ClassMap<UserRole>
{
public UserRoleMap()
{
Table("UserRoles");
CompositeId()
.KeyReference(x => x.User, "USER_LOGIN")
.KeyReference(x => x.Role, "ROLE_ID");
Map(x => x.Active).Column("ROLE_IS_ACTIVE");
}
}
一个用户可以有多个角色,一个角色可以有多个用户。就像我说的,经典的多对多。但是,UserRoles表还包含一个字段"active",我的应用程序
一切正常工作,但我认为nhibernate产生了太多的查询。当我选择一个用户并访问其角色时,显示的查询如下在Nhibernate分析器中:
SELECT user0_.USER_LOGIN as USER_LOGIN0_0_,
user0_.USER_NAME as USER_NAME_0_
FROM Users user0_
WHERE user0_.USER_ID = 'testuser'
-- Fetch the user
SELECT userrole0_.USER_LOGIN as USER_LOGIN1_,
userrole0_.ROLE_ID as ROLE_ID1_,
userrole0_.ROLE_ID as ROLE_ID1_0_,
userrole0_.USER_LOGIN as USER_LOGIN1_0_,
userrole0_.ROLE_IS_ACTIVE as ROLE_IS_ACTIVE1_0_
FROM UserRoles userrole0_
WHERE userrole0_.USER_LOGIN = 'testuser'
-- Fetch the roles for that user (why are some fields selected twice?)
-- returns three rows: roleids: 1, 2 and 3
SELECT userrole0_.ROLE_ID as ROLE_ID1_0_,
userrole0_.USER_LOGIN as USER_LOGIN1_0_,
userrole0_.ROLE_IS_ACTIVE as ROLE_IS_ACTIVE1_0_
FROM UserRoles userrole0_
WHERE userrole0_.USER_LOGIN = 'testuser'
and userrole0_.ROLE_ID = 1
SELECT userrole0_.ROLE_ID as ROLE_ID1_0_,
userrole0_.USER_LOGIN as USER_LOGIN1_0_,
userrole0_.ROLE_IS_ACTIVE as ROLE_IS_ACTIVE1_0_
FROM UserRoles userrole0_
WHERE userrole0_.USER_LOGIN = 'testuser'
and userrole0_.ROLE_ID = 2
SELECT userrole0_.ROLE_ID as ROLE_ID1_0_,
userrole0_.USER_LOGIN as USER_LOGIN1_0_,
userrole0_.ROLE_IS_ACTIVE as ROLE_IS_ACTIVE1_0_
FROM UserRoles userrole0_
WHERE userrole0_.USER_LOGIN = 'testuser'
and userrole0_.ROLE_ID = 3
-- Fetch all rows again separately but with full key?!?!!?
Nhibernate从取回我的User: OK开始接下来,它为该用户获取角色:OK但是,随后将检索第二个查询返回的每一行又是来自DB !我不知道为什么会这样,因为从第二个返回的数据查询实际上包含了足够的数据来填充NHibernate的整个UserRole对象。
有没有人可以:
- 给我解释一下为什么会这样
- 帮我想想怎么预防这一点。也就是说,我想告诉你NHibernate那是附加的对UserRoles表的查询如下没有必要。
非常感谢!问候,ldx
你可以改变NHibernate中延迟加载集合的抓取行为。您可以通过指定fetch
属性在映射中做到这一点:
<many-to-one name="UserRoles" column="ROLE_ID" class="Roles" fetch="select" lazy="false" not-null="true" cascade="save-update" />
我相信你也可以用Fluent做到这一点,但是我不知道这个方法。
你也可以通过在你的ICriteria
criteria.SetFetchMode ("UserRoles", FetchMode.Join);
没有直接回答你的问题…
从一侧将其映射为组件,从另一侧将其映射为反向多对多可能更容易:
用户:<bag name="UserRoles" table="UserRoles">
<key name="USER_LOGIN"/>
<composite-element>
<many-to-one name="Role" column="ROLE_ID"/>
<property name="Active" />
</composite-element>
</bag>
角色:
<bag name="Users" inverse="true" table="UserRoles">
<key name="ROLE_ID"/>
<many-to-many class="User" column="USER_LOGIN"/>
</bag>
- 不需要复合id
- 你不需要单独映射UserRoles
- 您可以在两个方向上导航(但您只能从
User.UserRoles
看到Active
标志)
- 这可能是因为你没有在你的映射类中指定不要对你的关系使用延迟加载。
作为点1,你可以指定不使用延迟加载在你的映射类,如
公共MyClassMap ()
{
表 ("...");
Id(…);
地图(…);
HasMany (x => x…).KeyColumn("…").Not.LazyLoad ();
}
在你的查询中,如果你使用QueryOver语句,你也可以使用。future ();而不是。list ();