2012-04-27 5 views
0

У меня есть веб-служба C# .Net. Я вызываю dll (C# .Net), который использует nHibernate для подключения к моей базе данных. Когда я вызываю dll, он выполняет запрос к db и загружает родительский объект «Задача». Однако, когда длл пытается получить доступ к дочерним объектам «Task.SubTasks», он выдает следующее сообщение об ошибке:Веб-служба nHibernate SessionFactory issue

NHibernate.HibernateException failed to lazily initialize a collection of role: SubTasks no session or session was closed 

Я новичок в NHibernate так что не уверен, что часть кода, я пропускаю.

Должен ли я запускать заводскую сессию в своем веб-сервисе перед вызовом dll? Если да, то как мне это сделать?

EDIT: Добавлен код веб-службы и код метода CreateContainer(). Этот код вызывается непосредственно перед вызовом DLL

[WebMethod] 
    public byte[] GetTaskSubtask (string subtaskId) 
    { 
     var container = CreateContainer(windsorPath); 

     IoC.Initialize(container); 
     //DLL CALL 
     byte[] theDoc = CommonExport.GetSubtaskDocument(subtaskId); 

     return theDoc; 

    } 

/// <summary> 
/// Register the IoC container. 
/// </summary> 
/// <param name="aWindsorConfig">The path to the windsor configuration 
/// file.</param> 
/// <returns>An initialized container.</returns> 
protected override IWindsorContainer CreateContainer(
    string aWindsorConfig) 
{ 
    //This method is a workaround. This method should not be overridden. 
    //This method is overridden because the CreateContainer(string) method 
    //in UnitOfWorkApplication instantiates a RhinoContainer instance that 
    //has a dependency on Binsor. At the time of writing this the Mammoth 
    //application did not have the libraries needed to resolve the Binsor 
    //dependency. 

    IWindsorContainer container = new RhinoContainer(); 

    container.Register(
     Component.For<IUnitOfWorkFactory>().ImplementedBy 
      <NHibernateUnitOfWorkFactory>()); 
    return container; 
} 

EDIT: Добавление кода DLL и код хранилища ...

DLL Код

public static byte[] GetSubtaskDocument(string subtaskId) 
{ 
    BOESubtask task = taskRepo.FindBOESubtaskById(Guid.Parse(subtaskId)); 

    foreach(subtask st in task.Subtasks) <--this is the line that throws the error 
    { 
    //do some work 
    } 


} 

Repository для задачи

/// <summary> 
/// Queries the database for the Subtasks whose ID matches the 
/// passed in ID. 
/// </summary> 
/// <param name="aTaskId">The ID to find matching Subtasks 
/// for.</param> 
/// <returns>The Subtasks whose ID matches the passed in 
/// ID (or null).</returns> 
public Task FindTaskById(Guid aTaskId) 
{ 
    var task = new Task(); 
    using (UnitOfWork.Start()) 
    { 
     task = FindOne(DetachedCriteria.For<Task>() 
        .Add(Restrictions.Eq("Id", aTaskId))); 
     UnitOfWork.Current.Flush(); 
    } 
    return task; 
} 

Репозиторий подзадачи

/// <summary> 
/// Queries the database for the Subtasks whose ID matches the 
/// passed in ID. 
/// </summary> 
/// <param name="aBOESubtaskId">The ID to find matching Subtasks 
/// for.</param> 
/// <returns>The Subtasks whose ID matches the passed in 
/// ID (or null).</returns> 
public Subtask FindBOESubtaskById(Guid aSubtaskId) 
{ 
    var subtask = new Subtask(); 
    using (UnitOfWork.Start()) 
    { 
     subtask = FindOne(DetachedCriteria.For<Subtask>() 
        .Add(Restrictions.Eq("Id", aSubtaskId))); 
     UnitOfWork.Current.Flush(); 
    } 
    return subtask; 
} 

ответ

1

Вы, очевидно, отобразили коллекцию в одном из классов данных NHibernate с включенной ленивой загрузкой (или лучше: не отключено, так как это поведение по умолчанию). NHibernate загружает объект и создает прокси для сопоставленных коллекций. Как только они будут доступны, NHibernate пытается загрузить элементы для этой коллекции. Но если вы закроете сеанс NHibernate до этого, произойдет ошибка, которую вы получили. Вероятно, вы подвергаете свой объект данных через веб-службу клиенту веб-службы. Во время процесса сериализации XmlSerializer пытается сериализовать коллекцию, которая запрашивает NHibernate для ее заполнения. Когда сеанс закрыт, возникает ошибка.

Два способа предотвратить это:

  • закрыть сессию после того, как ответ был послан

или

  • отключить отложенной загрузки для ваших коллекций, так что они загружаются мгновенно

Добавление после вышеуказанных изменений:

В вашем репозитории вы начинаете UnitsOfWork в рамках использования-инструкции. Они удаляются, как только код будет завершен. Я не знаю, как реализовать UnitOfWork, но я предполагаю, что он контролирует время жизни сеанса NHibernate. Утилизируя UnitOfWork, вы, вероятно, закрываете сеанс NHibernate. Поскольку ваше сопоставление инициализирует ленивые коллекции, эти коллекции еще не заполнены и возникает ошибка. NHibernate нуждается в точном экземпляре сеанса, который загрузил объект для заполнения лениво инициализированных коллекций.

У вас возникнут такие проблемы, если вы используете ленивую загрузку и имеете репозиторий, который закрывает сеанс до завершения ответа.Один из вариантов - инициализировать UnitOfWork в начале запроса и закрыть его после завершения ответа (например, в Application_BeginRequest, Application_EndRequest в Global.asax.cs). Это, конечно же, означает тесную интеграцию вашего репозитория в веб-службу.

В любом случае создание сеанса для одного запроса в сочетании с ленивой загрузкой является плохой идеей и, скорее всего, создаст подобные проблемы в будущем. Если вы не можете изменить реализацию репозитория, возможно, вам придется отключить ленивую загрузку.

+0

благодарит за отзыв. Но, думаю, моя проблема на более высоком уровне. У меня нет кода сеанса nHibernate. Я открываю контейнер с помощью Windsor, но не сеанс. Код, который бросает ошибку, находится в самой dll. Веб-служба инициализирует контейнер, а затем вызывает DLL. Dll захватывает объекты из db и возвращает их в качестве байта [] в веб-службу, но до тех пор, пока она не попадет туда. – MikeTWebb

+0

, но в какой-то момент кто-то открывает и закрывает сеанс NHibernate. И поскольку ошибка говорит о том, что NHibernate жалуется на закрытую сессию, ее, должно быть, кто-то открыл и закрыл. Какие части Виндзора вы используете? ActiveRecord, WCF Facility, NHibernate Integration? –

+0

согласился ... это происходит «автоматически» где-то. И это nHibernate Integration. В hibernate.cfg есть раздел для . Я добавил код CreateContainer выше – MikeTWebb

0

Используя обратную связь Гарленда, я решил проблему. Я удалил (а) код UnitOfWork из хранилища в DLL и завернул Web Service вызов библиотеки в течение модов кода UnitOfWork смотрите ниже:

Web Service

[WebMethod] 
public byte[] GetSubtaskDocument (string subtaskId) 
{ 
    var container = CreateContainer(windsorString); 

    IoC.Initialize(container); 

    byte[] theDoc; 
    using (UnitOfWork.Start()) 
    { 
     //DLL call 
     theDoc = CommonExport.GetSubtaskDocument(subtaskId); 
     UnitOfWork.Current.Flush(); 
    } 
    return theDoc; 
} 

Repository вызова в DLL

public Subtask FindSubtaskById(Guid aSubtaskId) 
{ 
    return FindOne(DetachedCriteria.For<Subtask>() 
       .Add(Restrictions.Eq("Id", aSubtaskId))); 
}