Вопрос по nhibernate, fluent-nhibernate, asp.net-mvc – NHibernate - не удалось лениво инициализировать коллекцию ролей

19

У меня есть следующий, казалось бы, простой сценарий, однако яЯ все еще довольно новичок в NHibernate.

При попытке загрузить следующую модель для действия Edit на моем контроллере:

контроллер»Действие редактирования:

public ActionResult Edit(Guid id)
{
    return View(_repository.GetById(id));
}

Repository:

public SomeModel GetById(Guid id)
{
    using (ISession session = NHibernateSessionManager.Instance.GetSession())
        return session.Get(id);
}

Модель:

public class SomeModel
{
    public virtual string Content { get; set; }
    public virtual IList SomeOtherModel { get; set; }
}

Я получаю следующую ошибку:

не удалось лениво инициализировать коллекцию ролей: SomeOtherModel, ни одна сессия не была закрыта

Что мне здесь не хватает?

Ваш Ответ

3   ответа
20

GetById метод. (оператор using закрывает сеанс) Сеанс должен быть доступен в течение всей бизнес-транзакции.

Есть несколько способов добиться этого. Вы можете настроить NHibernate для использования метода GetCurrentSession фабрик сессий. Увидетьэто на nhibernate.info или жеэтот пост на Code Project.

public SomeModel GetById(Guid id)
{
    // no using keyword here, take the session from the manager which
    // manages it as configured
    ISession session = NHibernateSessionManager.Instance.GetSession();
    return session.Get<somemodel>(id);
}
</somemodel>

Я нене использовать это. Я написал свой собственный сервис транзакций, который позволяет следующее:

using (TransactionService.CreateTransactionScope())
{
  // same session is used by any repository
  var entity = xyRepository.Get(id);

  // session still there and allows lazy loading
  entity.Roles.Add(new Role());

  // all changes made in memory a flushed to the db
  TransactionService.Commit();
}

Однако, как вы реализуете, сеансы и транзакции должны жить столько же, сколько бизнес-транзакция (или системная функция). Если вы не можетене полагайтесь ни на изоляцию транзакций, ни на откат.

10

Вам нужно с нетерпением загрузитьSomeOtherModel коллекция, если вы собираетесь использовать ее перед закрытием сессии:

using (ISession session = NHibernateSessionManager.Instance.GetSession())
{
    return session
        .CreateCriteria<somemodel>()
        .CreateCriteria("SomeOtherModel", JoinType.LeftOuterJoin)
        .Add(Restrictions.Eq(Projections.Id(), id))
        .UniqueResult<somemodel>();
}
</somemodel></somemodel>

По умолчанию FluentNHibernateиспользует ленивую загрузку для сопоставлений коллекций. Другой вариант - изменить это поведение по умолчанию в вашем отображении:

HasMany(x => x.SomeOtherModel)
    .KeyColumns.Add("key_id").AsBag().Not.LazyLoad();

Обратите внимание, что если вы делаете этоSomeOtherModel будет загружаться (используя внешнее соединение) каждый раз, когда вы загружаете родительский объект, который может быть вам не нужен. В общем, я предпочитаю всегда оставлять ленивую загрузку по умолчанию на уровне отображения и настраивать свои запросы в зависимости от ситуации.

Я бы нене делайте этого, так как открытие транзакции для каждого вызова - плохая практика. Изоляция транзакции недоступна, кэш NHibernate больше не нужен (каждый вызов возвращает новый экземпляр), постоянное игнорирование невозможно, отложенная загрузка больше не работает. Короче говоря: большинство преимуществ использования NHibernate уничтожено ". Stefan Steinegger
1

), мы получаем исключение. Поскольку сессия закрыта, NHibernate не может лениво загружать позиции заказа для нас. Мы можем показать это поведение с помощью следующего метода тестирования ""

[Test]
[ExpectedException(typeof(LazyInitializationException))]
public void Accessing_customer_of_order_after_session_is_closed_throws()
{
  Order fromDb;
  using (ISession session = SessionFactory.OpenSession())
      fromDb = session.Get<order>(_order.Id);

  // trying to access the Customer of the order, will throw exception
  // Note: at this point the session is already closed
  string name = fromDb.Customer.CompanyName;
}
</order>

Легкая загрузка с помощью класса NHibernateUtil. Если вы знаете, что вам нужен доступ к связанным объектам объекта заказа, вы можете использовать класс NHibernateUtil для инициализации связанных объектов (то есть: для их извлечения из базы данных). "

[Test]
public void Can_initialize_customer_of_order_with_nhibernate_util()
{
    Order fromDb;

    using (ISession session = SessionFactory.OpenSession())
    {
       fromDb = session.Get<order>(_order.Id);

       NHibernateUtil.Initialize(fromDb.Customer);
    } 

    Assert.IsTrue(NHibernateUtil.IsInitialized(fromDb.Customer));
    Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb.OrderLines));

}
</order>

Ссылка:http://nhibernate.info/doc/howto/various/lazy-loading-eager-loading.html

Похожие вопросы