Проблема с NHibernate - PullRequest
       60

Проблема с NHibernate

0 голосов
/ 16 апреля 2010

Я пытаюсь получить список продуктов, которые разделяют категорию.

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

Вот мой метод Criteria API:

public IList<Product> GetProductForCategory(string name)
        {

            return _session.CreateCriteria(typeof(Product))
                .CreateCriteria("Categories")
                .Add(Restrictions.Eq("Name", name))
                .List<Product>();

        }

Вот мой метод HQL:

public IList<Product> GetProductForCategory(string name)
        {
            return _session.CreateQuery("select from Product p, p.Categories.elements c where c.Name = :name").SetString("name",name).List<Product>();


        }

Оба метода не возвращают продукт, если они должны вернуть 2 продукта.

Вот отображение для класса продукта:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CBL.CoderForTraders.DomainModel" namespace="CBL.CoderForTraders.DomainModel">
  <class name="Product" table="Products" >
    <id name="_persistenceId" column="ProductId" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="assigned" />
    </id>
    <version name="_persistenceVersion" column="RowVersion" access="field" type="int" unsaved-value="0" />

    <property name="Name" column="ProductName" type="String" not-null="true"/>
    <property name="Price" column="BasePrice" type="Decimal" not-null="true" />
    <property name="IsTaxable" column="IsTaxable" type="Boolean" not-null="true" />
    <property name="DefaultImage" column="DefaultImageFile" type="String"/>

    <bag name="Descriptors" table="ProductDescriptors">
      <key column="ProductId" foreign-key="FK_Product_Descriptors"/>
      <one-to-many class="Descriptor"/>
    </bag>
    <bag name="Categories"  table="Categories_Products" >
      <key column="ProductId" foreign-key="FK_Products_Categories"/>
      <many-to-many class="Category" column="CategoryId"></many-to-many>
    </bag>

    <bag name="Orders" generic="true" table="OrderProduct" >
      <key column="ProductId" foreign-key="FK_Products_Orders"/>
           <many-to-many column="OrderId" class="Order" />
    </bag>


  </class>
</hibernate-mapping>

И, наконец, отображение для класса Category:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CBL.CoderForTraders.DomainModel" namespace="CBL.CoderForTraders.DomainModel" default-access="field.camelcase-underscore" default-lazy="true">

  <class name="Category" table="Categories" >
    <id name="_persistenceId" column="CategoryId" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="assigned" />
    </id>
    <version name="_persistenceVersion" column="RowVersion" access="field" type="int" unsaved-value="0" />

    <property name="Name" column="Name" type="String" not-null="true"/>
    <property name="IsDefault" column="IsDefault" type="Boolean" not-null="true" />
    <property name="Description" column="Description" type="String" not-null="true" />

    <many-to-one name="Parent" column="ParentID"></many-to-one>

    <bag name="SubCategories" inverse="true">
      <key column="ParentID" foreign-key="FK_Category_ParentCategory" />
      <one-to-many class="Category"/>
    </bag>
    <bag name="Products" table="Categories_Products">
      <key column="CategoryId" foreign-key="FK_Categories_Products" />
      <many-to-many column="ProductId" class="Product"></many-to-many>
    </bag>
  </class>
</hibernate-mapping>

Вы видите, в чем может быть проблема?

если я удалю строку добавления, мой запрос:

return _session.CreateCriteria(typeof(Product))
                .CreateCriteria("Categories")
                .List<Product>();

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

Значит, что-то не так, когда я добавляю строку: .Add (Restrictions.Eq ("Имя", имя))

Вот Sql, сгенерированный, включая линию ограничения:

NHibernate: ВЫБЕРИТЕ this_.ProductId в качестве ProductId23_1_, this_.RowVersion в качестве RowVersion23_1_, this_.ProductName в качестве ProductN3_23_1_, this_.BasePrice в качестве BasePrice23_1_, this_.IsTmageable в качестве IsItable_1_1_1 CategoryId в качестве CategoryId, category1_.CategoryId в качестве CategoryId16_0_, category1_.RowVersion в качестве RowVersion16_0_, category1_.Name в качестве Name16_0_, category1_.IsDefault в качестве IsDefault16_0_, category1_.Description в качестве Descript5_ID______ для_1_1 = category3_.ProductId внутреннее объединение Категории category1_ on Categories3_.CategoryId = category1_.CategoryId WHERE category1_.Name = @ p0; @ p0 = 'Momemtum'

Ответы [ 4 ]

2 голосов
/ 16 апреля 2010

Трудно сказать только по запросу и сопоставлениям. Также интересно будет, как вы создаете данные.

HQL должен выглядеть примерно так:

select p
from Product p join p.Categories c 
where c.Name = :name

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

Кстати, вы можете (должны) отобразить двунаправленное отношение «многие ко многим» между товарами и категориями в одной и той же таблице, поскольку, скорее всего, это одни и те же данные. Просто сопоставьте его с той же таблицей / столбцами и установите одно из отношений «человек ко многим» inverse="true".

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

Чтобы найти такую ​​ошибку:

  • Посмотрите на сгенерированный SQL (в конфигурации установите show_sql на true. Вы увидите его в консоли.) Когда вы используете SqlServer, вы также можете использовать Profiler.
  • Выполнить запрос в консоли SQL.
  • Посмотрите на данные в базе данных.
1 голос
/ 16 апреля 2010

Ваш запрос Criteria выглядит хорошо - как и десятки, которые я написал.

Проблема в вашей таблице ссылок «многие ко многим».

В отображении Product у вас есть это:

<bag name="Categories"  table="Categories_Products" >
  <key column="ProductId" foreign-key="FK_Products_Categories"/>
  <many-to-many class="Category" column="CategoryId"></many-to-many>
</bag>

В отображении Category у вас есть это:

<bag name="Products" table="Categories_Products">
  <key column="CategoryId" foreign-key="FK_Categories_Products" />
  <many-to-many column="ProductId" class="Product"></many-to-many>
</bag>

Мне кажется, что вы изменили свои внешние ключи, связав ProductId с FK_Products_Categories вместо FK_Categories_Products.

Что-то, что я нахожу полезным в такой ситуации, - это включить ведение журнала SQL для NHibernate, а затем посмотреть на сгенерированный SQL. Обычно это дает мне довольно большую подсказку относительно моей ошибки отображения. Для получения дополнительной информации см. Настройка Log4Net для использования с NHibernate .

.
0 голосов
/ 17 апреля 2010

Очень жаль, ребята. Мое отображение и код в порядке. Проблема была в названии параметра.

0 голосов
/ 16 апреля 2010

попробуйте подзапрос, используя отдельные критерии, чтобы получить эквивалент следующего простого sql

select * from Products where ProductId in (select distinct cp.ProductId from Categories_Products cp inner join Categories c on cp.CategoryId = c.CategoryId and c.Name = name)

как то так ...

DetachedCriteria subCriteria = DetachedCriteria.For(typeof(Category))
    .SetResultTransformer(new DistinctRootEntityResultTransformer())
    .SetProjection(Projections.Property("Category.Products.ProductId"))
    .Add(Restrictions.PropertyEq("Name", name));

return _session.CreateCriteria.For(typeof(Product))
    .Add(Subqueries.PropertyIn("ProductId", subCriteria))
    .List<Product>();

Ack, Category.Products.ProductId может быть не верным, но, возможно, вы можете увидеть, что я пытаюсь сделать здесь, и выяснить правильную проекцию для использования в подзапросе.

...