我目前正在编写一个访问旧数据库的应用程序。 我正在使用nhibernate作为我的ORM。
DB中有三个表代表(几乎)经典的多对多关系。 由于视线不同,链接表还包含额外数据。
代码看起来像这样:
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 Profiler中:
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从获取用户开始:好的 接下来,它为该用户获取角色:OK 但是,然后检索第二个查询返回的每一行 再次来自DB! 我不知道为什么会这样,因为从第二个返回的数据 查询实际上包含足够的数据供NHibernate填充我的整个UserRole对象。
有没有人可以:
非常感谢! 问候, LDX
答案 0 :(得分:2)
您可以在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);
答案 1 :(得分:1)
不是你问题的直接答案......
将它从一侧映射为组件可能更容易,而从另一侧映射为多对多:
用户:
<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>
Active
看到User.UserRoles
标志)答案 2 :(得分:-1)
作为第1点,您可以指定不在映射类中使用延迟加载,如
public MyClassMap()
{
表( “...”);
ID(...);
地图(...);
HasMany(x =&gt; x ....)。KeyColumn(“...”)。Not.LazyLoad();
}
在您的查询中,如果您使用的是QueryOver Statement,则还可以使用.Future();而不是.List();
我认为它很有帮助。