NHibernate CompositeId =>查询太多了

时间:2011-04-07 13:12:38

标签: nhibernate fluent-nhibernate

我目前正在编写一个访问旧数据库的应用程序。 我正在使用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对象。

有没有人可以:

  1. 向我解释为什么会发生这种情况
  2. 帮我弄清楚如何预防 这个。即我想告诉你 NHibernate表示额外的 UserRoles表上的查询是 没必要。
  3. 非常感谢! 问候, LDX

3 个答案:

答案 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

中明确设置,覆盖您在mappping中指定的抓取行为
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>
  • 您不需要复合ID
  • 您无需单独映射UserRoles
  • 您可以双向导航(但只能从Active看到User.UserRoles标志)

答案 2 :(得分:-1)

  1. 它可能是因为您没有在映射类中指定不为您的关系使用延迟加载。
  2. 作为第1点,您可以指定不在映射类中使用延迟加载,如

    public MyClassMap()

    {

    表( “...”);

    ID(...);

    地图(...);

    HasMany(x =&gt; x ....)。KeyColumn(“...”)。Not.LazyLoad();

    }

  3. 在您的查询中,如果您使用的是QueryOver Statement,则还可以使用.Future();而不是.List();

    我认为它很有帮助。