Я впервые использую NHibernate (версия 1.2.1), поэтому я написал простое тестовое приложение (проект ASP.NET), которое его использует.В моей базе данных есть две таблицы: Персоны и Категории.Каждый человек получает одну категорию, кажется достаточно легкой.
<code>
| Persons | | Categories |
|--------------| |--------------|
| Id (PK) | | Id (PK) |
| Firstname | | CategoryName |
| Lastname | | CreatedTime |
| CategoryId | | UpdatedTime |
| CreatedTime | | Deleted |
| UpdatedTime |
| Deleted |
Атрибуты Id, CreatedTime, updatedTime и Deleted - это соглашение, которое я использую во всех своих таблицах, поэтому я попытался перенести этот факт на дополнительный уровень абстракции.У меня есть проект DatabaseFramework, который имеет три важных класса:
- Entity: абстрактный класс, который определяет эти четыре свойства.Все «объекты сущностей» (в данном случае Person и Category) должны наследовать Entity.
- IEntityManager: универсальный интерфейс (параметр типа как Entity), который определяет такие методы, как Load, Insert, Update и т. Д.
- NHibernateEntityManager: реализация этого интерфейса, использующая NHibernate для загрузки, сохранения и т. Д.
Теперь классы Person и Category просты, они, конечно, просто определяют атрибуты таблиц (с учетомчто четыре из них находятся в базовом классе Entity).
Поскольку таблица Persons связана с таблицей Categories через атрибут CategoryId, класс Person имеет свойство Category, которое содержит связанную категорию.Однако на моей веб-странице мне также понадобится название этой категории (CategoryName), например, для привязки данных.Поэтому я создал дополнительное свойство CategoryName, которое возвращает свойство CategoryName текущего свойства Category, или пустую строку, если Category имеет значение null:
Namespace Database
Public Class Person
Inherits DatabaseFramework.Entity</p>
<pre><code> Public Overridable Property Firstname As String
Public Overridable Property Lastname As String
Public Overridable Property Category As Category
Public Overridable ReadOnly Property CategoryName As String
Get
Return If(Me.Category Is Nothing, _
String.Empty, _
Me.Category.CategoryName)
End Get
End Property
End Class
Конечное пространство имен
Я сопоставляю класс Person с помощью этого файла сопоставления.Отношение «многие к одному» было предложено Ядсом в другой ветке:
</p>
<p></p>
<pre><code><id name="Id" column="Id" type="int" unsaved-value="0">
<generator class="identity" />
</id>
<property name="CreatedTime" type="DateTime" not-null="true" />
<property name="UpdatedTime" type="DateTime" not-null="true" />
<property name="Deleted" type="Boolean" not-null="true" />
<property name="Firstname" type="String" />
<property name="Lastname" type="String" />
<many-to-one name="Category" column="CategoryId" class="NHibernateWebTest.Database.Category, NHibernateWebTest" />
(я не могу заставить его показать корневой узел, этот форум скрывает его, яне знаю, как избежать html-подобных тегов ...)
Последней важной деталью является метод Load реализации NHibernateEntityManager.(Это в C #, как в другом проекте, извините за это).
Я просто открываю новую ISession (ISessionFactory.OpenSession) в методе GetSession, а затем использую это для заполнения EntityCollection (Of TEntity), который простоколлекция, унаследованная System.Collections.ObjectModel.Collection (Of T).
<code>
public virtual EntityCollection< TEntity > Load()
{
using (ISession session = this.GetSession())
{
var entities = session
.CreateCriteria(typeof (TEntity))
.Add(Expression.Eq("Deleted", false))
.List< TEntity >();
return new EntityCollection< TEntity >(entities);
}
}
(Опять же, я не могу заставить ее правильно отформатировать код, она скрывает параметры универсального типа, вероятно,потому что он читает угловые символы как тег HTML ...? Если вы знаете, как мне это сделать, дайте мне знать!)
Теперь идея этого метода Load состоит в том, что я получаю полностью функциональную коллекциюof Persons, все их свойства установлены в правильные значения (включая свойство Category, и, следовательно, свойство CategoryName должно возвращать правильное имя).
Однако, похоже, что это не так.Когда я пытаюсь связать данные результата этого метода Load с GridView в ASP.NET, он говорит мне следующее:
Property accessor 'CategoryName' on object 'NHibernateWebTest.Database.Person' threw the following exception:'Could not initialize proxy - the owning Session was closed.'
Исключение происходит при вызове метода DataBind здесь:
public virtual void LoadGrid()
{
if (this.Grid == null) return;</p>
<pre><code> this.Grid.DataSource = this.Manager.Load();
this.Grid.DataBind();
}
Ну, конечно, сессия закрыта, я закрыл ее с помощью блока using.Разве это не правильный подход, я должен держать сессию открытой?И как долго?Могу ли я закрыть его после запуска метода DataBind?
В каждом случае мне бы очень хотелось, чтобы мой метод Load просто возвращал функциональную коллекцию элементов.Мне кажется, что теперь он получает категорию только тогда, когда это требуется (например, когда GridView хочет прочитать CategoryName, который хочет прочитать свойство Category), но в это время сеанс закрыт.Это рассуждение правильно?
Как мне остановить это поведение?Или я не должен?А что мне делать иначе?
Спасибо!