NHibernate CompositeId => слишком много запросов - PullRequest
1 голос
/ 07 апреля 2011

В настоящее время я пишу приложение, которое обращается к устаревшей базе данных.Я использую 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», которое требуется моему приложению для правильной работы.

Все работает правильно, но IMHO 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. Затем он выбирает роли для этого пользователя:Хорошо. Но затем каждая строка, возвращаемая этим вторым запросом, снова извлекается из БД!Я не знаю, почему это происходит, поскольку данные, возвращаемые во втором запросе, на самом деле содержат достаточно данных для NHibernate, чтобы заполнить весь мой объект UserRole.

Есть ли кто-нибудь, кто может:

  1. объясните мне, почему это происходит
  2. помогите мне понять, как это предотвратить.то есть я хотел бы просто сказать NHibernate, что дополнительные запросы к таблице UserRoles не нужны.

Большое спасибо!С уважением, ldx

Ответы [ 3 ]

2 голосов
/ 07 апреля 2011

Вы можете изменить поведение выборки в 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 голос
/ 07 апреля 2011

Не прямой ответ на ваш вопрос ...

Может быть проще отобразить его как компонент с одной стороны и обратное соотношение многие ко многим с другой:

Пользователь:

<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)
0 голосов
/ 07 апреля 2011
  1. вероятно, потому что вы не указали в своем классе отображения, чтобы не использовать ленивую нагрузку для ваших отношений.
  2. в качестве точки 1 вы можете указать, чтобы не использовать ленивую нагрузку в вашем классе отображения, например

    public MyClassMap ()

    {

    Таблица ( "...");

    Id (...);

    Карта (...);

    HasMany (x => x ....). KeyColumn ("..."). Not.LazyLoad ();

    }

В вашем запросе, если вы используете оператор QueryOver, вы также можете использовать .Future (); вместо .List ();

Дырка это полезно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...