Почему я не могу ссылаться на дочерние сущности с помощью части составного ключа родительских сущностей - PullRequest
2 голосов
/ 23 февраля 2010

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

Я получаю следующую ошибку

Внешний ключ в таблице VolatileEventContent должен иметь то же самое количество столбцов как указано первичный ключ в таблице LocationSearchView

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="JeanieMaster.Domain.Entities" assembly="JeanieMaster.Domain">
  <class name="LocationSearchView" table="LocationSearchView">

    <composite-id>
      <key-property name="LocationId" type="Int32"></key-property>
      <key-property name="ContentProviderId" type="Int32"></key-property>
      <key-property name="CategoryId" type="Int32"></key-property>
    </composite-id>

    <property name="CompanyName" type="String" not-null="true" update="false" insert="false"/>
    <property name="Description" type="String" not-null="true" update="false" insert="false"/>
    <property name="CategoryId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="ContentProviderId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="LocationId" type="Int32" not-null="true" update="false" insert="false"/>
    <property name="Latitude" type="Double"  update="false" insert="false" />
    <property name="Longitude" type="Double"  update="false" insert="false" />

    <bag name="Events" table="VolatileEventContent" where="DeactivatedOn IS NULL" order-by="StartDate DESC" lazy="false" cascade="none">
      <key>
        <column name="LocationId"></column>
        <column name="ContentProviderId"></column>
        <!--<column name="LocationId"></column>
        <column name="ContentProviderId"></column>
        <column name="CategoryId"></column>-->
      </key>
      <one-to-many class="Event" column="VolatileEventContentId"></one-to-many>
    </bag>

  </class>
</hibernate-mapping>

И файл сопоставления VolatileEventContent

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="JeanieMaster.Domain.Entities" assembly="JeanieMaster.Domain">
  <class name="Event" table="VolatileEventContent" select-before-update="false" optimistic-lock="none">
    <composite-id>
      <key-property name="LocationId" type="Int32"></key-property>
      <key-property name="ContentProviderId" type="Int32"></key-property>
    </composite-id>

    <property name="Description" type="String" not-null="true" update="false" insert="false"/>

    <property name="StartDate" type="DateTime" not-null="true" update="false" insert="false" />
    <property name="EndDate" type="DateTime" not-null="true" update="false" insert="false" />

    <property name="CreatedOn" type="DateTime" not-null="true" update="false" insert="false" />
    <property name="ModifiedOn" type="DateTime" not-null="false" update="false" insert="false" />

    <many-to-one name="Location" class="Location" column="LocationId" />

    <bag name="Artistes" table="EventArtiste" lazy="false" cascade="none">
      <key name="VolatileEventContentId" />
      <many-to-many class="Artiste" column="ArtisteId" ></many-to-many>
    </bag>
  </class>
</hibernate-mapping>

Ответы [ 3 ]

2 голосов
/ 20 марта 2010

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

CREATE TABLE LocationSearchView (
    LocationId int NOT NULL,
    ContentProviderId int NOT NULL,
    CategoryId int NOT NULL,

    /* ...other columns... */

    /* Note: Generated from LocationSearchView's "composite-id" element.  */
    PRIMARY KEY (LocationId, ContentProviderId, CategoryId)
);

/* Note: Table for the "Event" class. */
CREATE TABLE VolatileEventContent (
    LocationId int NOT NULL,
    ContentProviderId int NOT NULL,

    /* ...other columns... */

    /* Note: Generated from Event's "composite-id" element. */
    PRIMARY KEY (LocationId, ContentProviderId),
    /* Note: Generated from the "key" element of LocationSearchView's Events bag. */
    FOREIGN KEY (LocationId, ContentProviderId) REFERENCES LocationSearchView (LocationId, ContentProviderId)
);

... отсюда ошибка.Внешний ключ должен указывать на полный первичный или уникальный ключ, а не только на часть первичного ключа.Весь ключ - 3 столбца, а не 2. Почему NHibernate использует эти столбцы для внешнего ключа?Из-за <key> элемента LocationSearchView Events сумки.<key> указывает, какие столбцы из child указывают на parent .

Давайте рассмотрим, что может произойти, если вы (или NHibernate) попытаетесь выбрать из этих таблиц,Допустим, следующие данные:

TABLE LocationSearchView
LocationId ContentProviderId CategoryId
========== ================= ==========
1          3                 5
1          3                 6
1          4                 5
1          4                 6
2          3                 5
2          3                 6
2          4                 5
2          4                 6
TABLE VolatileEventContent
LocationId ContentProviderId
========== =================
1          3
1          4
2          3
2          4

Невозможно, чтобы «один» LocationSearchView имел «много» * ​​1021 * с.Скорее, должно быть наоборот.Учитывая эти таблицы, на самом деле существует отношение один ко многим от Event до LocationSearchView.

Я не знаю, как правильно решить эту проблему, потому что я не знаю, чтоВы пытаетесь выполнить, но, надеюсь, это поможет осветить, в чем именно проблема.

0 голосов
/ 26 марта 2010

Прежде всего у вас есть ошибка в вашем отображении для "LocationSearchView" Вы определяете столбец CategoryId как Свойство и часть Composite-id. Это неправильно, но, к сожалению, оно не улавливается при построении сопоставления и обычно отображается при запросе объекта. check IndexOutOfRangeException Глубоко в недрах NHibernate

Это может сбить с толку анализатор отображения. И я говорю , сбивающий с толку , потому что в обоих ваших отображениях вы полагаетесь на Отражение и Конвенцию, которые подразумевают более дисциплинированную методологию программирования:

  1. Вы явно не определяете атрибут class элементов many-to-one и bag, но вместо этого вы ожидаете от NHibernate обнаружить тип класса из самого определения класса. Если по какой-либо причине вы установили класс LocationSearchView, следующий IList<LocationSearchView> Events {get;set;} nhibernate будет ожидать найти класс LocationSearchView для определенного bag и, следовательно, потребует 3 столбца для сопоставления коллекции
  2. У вас есть одинаковые имена свойств для имен столбцов, что облегчает разработку (на самом деле это только облегчает создание отображений, которые вы делаете только один или два раза в любом случае), но в случае ошибок или изменений затрудняет обнаружение того, что пошло не так.

Итак, сделайте ваши сопоставления богаче и уберите ошибку, о которой я упоминал с CategoryId, также включите классы в ваш пост!

0 голосов
/ 20 марта 2010

Я никогда не использовал nhibernate, но я думаю, что отображение очень похоже на hibernate.

Если вы не хотите, чтобы ваша ассоциация «один ко многим» (LocationSearchView to many VolatileEventContent) использовала идентификатор LocationSearchView, вам необходимо определить в ключевом элементе пакета атрибут «property-ref», который определит свойство для использования вместо:

<bag name="Events" table="VolatileEventContent" ...>
  <key property-ref="partialId">
    <column name="LocationId"></column>
    <column name="ContentProviderId"></column>
  </key>
  <one-to-many class="Event" column="VolatileEventContentId"></one-to-many>
</bag>

(атрибут столбца допустим для тега один ко многим?)

Теперь вам нужно определить свойство с таким именем, примерно так:

<properties name="partialId" insert="false" update="false">
  <property name="LocationId" type="Int32" update="false" insert="false"/>
  <property name="ContentProviderId" type="Int32" update="false" insert="false"/>
</properties>

Вы уже определили LocationId и ContentProviderId. Просто переместите эти два свойства в элемент свойств.

...