Простая связь между двумя таблицами - PullRequest
0 голосов
/ 12 января 2011

Я начал использовать 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 в таблице категорий).Мне не нужен класс 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)

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

Работает нормально, если я опускаю отображение категории «многие к одному» в отображении Person, но, очевидно, свойство Category всегда имеет значение null.

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

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

Ответы [ 2 ]

0 голосов
/ 13 января 2011

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

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

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

"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();
    }

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

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

<code>        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, когда захочу?

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

0 голосов
/ 13 января 2011

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

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

UPDATE : В ваших сопоставлениях отсутствует полное имя сопоставленного класса в теге. Смотри http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-class

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

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

...