Простая связь между двумя таблицами

Я начал использовать NHibernate сегодня, но не могу понять, как настроить простое отношение между двумя таблицами. Я действительно не знаю, как это называется, это может быть отношение "один ко многим" или "внешний ключ" (я не имею в виду дизайн базы данных и используемые термины), но вот очень простой пример.

У меня есть таблица Product с атрибутами Id (PK), ProductName и CategoryId. Тогда у меня есть таблица Категории с атрибутами Id (PK) и CategoryName.

Я создал эти классы:

public class Product
{
    public virtual int Id { get; set; }  
    public virtual string ProductName { get; set; }  
    public virtual int CategoryId { get; set; }  

    public virtual Category Category { get; set; }  

    public virtual string CategoryName  
    {  
        get { return this.Category == null ? String.Empty : this.Category.CategoryName; } 
    }
}

public class Category  
{  
    public virtual int Id { get; set; }
    public virtual string CategoryName { get; set; }
}

Другими словами, я просто хочу, чтобы Продукт сохранял, к какой категории он принадлежит (через атрибут CategoryId, который указывает на Id в таблице Categories). Мне не нужен класс Category для хранения списка связанных продуктов, если это делает его немного проще.

Чтобы еще яснее понять, что мне нужно, вот SQL, который я ожидаю:

SELECT Products.*, Categories.*
FROM Products INNER JOIN Categories ON Products.CategoryId = Categories.Id

по крайней мере, я так думаю (опять же, я не очень хорош в дизайне базы данных или запросах).

Я не могу понять, какой вид картографии мне нужен для этого. Я полагаю, мне нужно сопоставить его в файле Product.hbm.xml. Но я также сопоставляю CategoryId? И как мне сопоставить свойство категории?

Похоже, мне нужно отношение "один ко многим", поскольку у меня есть ОДНА категория для каждого продукта (или это рассуждение в обратном направлении?), Но кажется, что нет сопоставления "один ко многим"...

Спасибо за любую помощь!

Дополнение:

Я попытался добавить отношение "многие к одному" в сопоставлении "Персона", но получаю исключение, в котором говорится "Ошибка создания прокси-сервера", а во внутреннем исключении - "Неопределенное совпадение найдено".

Возможно, мне следует упомянуть, что я использую старую версию NHibernate (1.2, я думаю), потому что это единственная версия, которую я запустил с MS Access, поскольку он не обнаружил JetDriver в более новых версиях.

Я поместил файлы сопоставления, классы и код, где ошибка возникает на скриншотах, потому что я не могу понять, как разместить здесь XML-код... Он продолжает читать его как теги html и пропускает половину его. Тем не мение.

Отображения:
http://www.nickthissen.nl/Images/tmp7B5A.png

Классы:
http://www.nickthissen.nl/Images/tmpF809.png

Код загрузки, где происходит ошибка:
http://www.nickthissen.nl/Images/tmp46B6.png
(Как я уже сказал, внутреннее исключение гласит: "Неоднозначное совпадение найдено".

(Продукт в моем примере был заменен человеком)

Классы Person и Category наследуют Entity, который является абстрактным базовым классом и определяет свойства Id, Deleted, CreatedTime и updatedTime. Код, в котором происходит ошибка, находится в общем классе 'manager' (параметр типа TEntity, который должен наследовать Entity). Просто предполагается загрузить все объекты с атрибутом Deleted false. В этом случае TEntity - это "Персона".

Это прекрасно работает, если я опускаю отображение категории "многие к одному" в отображении "Персона", но, очевидно, свойство "Категория" всегда равно нулю.

О да, извините за смесь между C# и VB, код C# находится в общей структуре, которую я использую для нескольких проектов, в то время как часть VB - это фактическая реализация этой инфраструктуры на моем веб-сайте, и я только что использовал VB для этого.

Помогите? Спасибо!

2 ответа

Решение

В вашем классе Product должен содержаться только объект Category, вам не нужно свойство CategoryId. Тогда в вашем картографировании товаров вы должны иметь эту запись

<many-to-one name="Category" column="CategoryId" />

ОБНОВЛЕНИЕ: в ваших сопоставлениях отсутствует полное имя сопоставленного класса в теге. См. http://nhibernate.info/doc/nh/en/index.html

ОБНОВЛЕНИЕ 2:

Посмотрите, поможет ли вам NHibernate 1.2 в решении.NET 4.0

Исключение "Обнаружено неоднозначное соответствие" было вызвано проектом, нацеленным на.NET Framework 4, который, похоже, не совместим с NHibernate 1.2.1. Я перешел на 3.5, и это, кажется, решить эту конкретную проблему.

Теперь перейдем к следующему. Как видите, у класса Person есть свойство CategoryName, которое должно возвращать имя текущего объекта Category, или пустую строку, если категория оказывается пустой. Это сделано для того, чтобы я мог привязать коллекцию объектов Person к сетке, указав "CategoryName" в качестве свойства, к которому нужно привязать столбец.

По-видимому, это не работает с NHibernate. Всякий раз, когда я пытаюсь связать свою коллекцию людей с данными, я получаю это исключение:

 "Средство доступа к свойству" CategoryName "для объекта" NHibernateWebTest.Database.Person "вызвало следующее исключение:" Не удалось инициализировать прокси-сервер - сеанс-владелец был закрыт "." 

Это происходит при вызове метода "DataBind" в этом коде:

        public virtual void LoadGrid()
        {
            if (this.Grid == null) return;

        this.Grid.DataSource = this.Manager.Load();
        this.Grid.DataBind();
    }

(Это проект ASP.NET, а Grid - это GridView)

this.Manager возвращает существующий экземпляр NHibernateEntityManager, и я уже показал его метод Load, который содержит следующее:

        public virtual EntityCollection Load()
        {
            using (ISession session = this.GetSession())
            {
                var entities = session
                                .CreateCriteria(typeof (TEntity))
                                .Add(Expression.Eq("Deleted", false))
                                .List();
                return new EntityCollection(entities);
            }
        }

(Там есть некоторые общие параметры типа, но этот веб-сайт, кажется, скрывает их (из-за тегов типа html, я думаю)... Извините за это).

Это может иметь какое-то отношение к самому NHibernate, как я уже сказал, я совершенно новичок в этом. Когда я вызываю свой метод Load, я ожидаю, что он вернет EntityCollection(Of Person) со всеми уже установленными свойствами. Кажется, я должен держать ISession открытой, пока я по какой-то причине связываю данные..? Это кажется немного странным...
Могу ли я обойти это? Могу ли я сделать так, чтобы метод Load просто возвращал коллекцию людей, уже полностью загруженных, чтобы я мог получить доступ к CategoryName, когда захочу?

Подожди... Может, это ленивая загрузка?

Другие вопросы по тегам