NHibernate - при добавлении объекта в коллекцию «многие ко многим» существующие объекты удаляются и повторно вставляются - PullRequest
2 голосов
/ 01 декабря 2010

Я использую таблицу сопоставления «многие ко многим», которая сопоставляет поля с объектами.

Соответствующая структура БД ...

Объекты: Таблица
(pk) objectId
[остальное не имеет значения]

Поля: таблица
(pk) fieldId
[остальное не имеет значения]

ObjectFields: Table
(pk) fieldObjectid (fk) fkObjectId -> Objects (fk) fkFieldId -> Fields

Мое отображение выглядит следующим образом:

<bag name="Fields" table="ObjectFields" lazy="true" cascade="all">
  <key column="fkObjectId"/>
  <many-to-many class="Field" column="fkFieldId" />
</bag>

Теперь все операции сбора работают так, как вы ожидаете - извлечение, добавление и удаление,Однако происходит очень странная вещь.Если я добавляю объект в коллекцию «Поля», NHibernate удаляет то, что уже есть, и повторно вставляет его.

Вот мой дамп log4net: DEBUG NHibernate.SQL [(null)] - ВЫБЕРИТЕ this_.objectId как objectId6_0_, this_.Name как Name6_0_, this_.Description как Descript3_6_0_, this_.RootElement как RootElem4_6_0_, this_.ChildElement как ChildEle5_6_0_, this_.ImageUrl как ImageUrl6_0, this_._h_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_с_илию, в этом_из_обозначении_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения_обозначения@ p0; @ p0 = 5 [Тип: Int32 (0)]
ОТЛАДКА NHibernate.SQL [(null)] - ВЫБРАТЬ fields0_.fkObjectId как fkObjectId1_, fields0_.fkFieldId как fkFieldId1_, inventoryf1_.fieldId как fieldId4_0.field_Nameкак fieldName4_0_, inventoryf1_.fieldType как fieldType4_0_, inventoryf1_. Обязательный как Обязательный4_0_ FROM ObjectFields fields0_ оставил внешнее соединение Поля inventoryf1_ для fields0_.fkFieldId = inventoryf1_.fieldId WHERE fields0_.fkObjectId=0 = 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0; 0 = 0; 0 = 0; 0 = 0; 0 = 0; 0: 0 = 0; 0 = 0: 0 = 0: 0 = 0: 0 = 0 = 0 (0) = 0 (0) = 0: 0 = 0 = 0 = 0; 0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 (0
DEBUG NHibernate.SQL [(null)] -ВЫБЕРИТЕ this_.fieldId в качестве fieldId4_0_, this_.fieldName в качестве fieldName4_0_, this_.fieldType в качестве fieldType4_0_, this_.Required as Required4_0_ FROM Поля this_ ГДЕ this_.fieldId = @ p0; @ p0 = 2 [Тип: Int32 (0)DEBUG NHibernate.SQL [(null)] - УДАЛИТЬ ИЗ ObjectFields, ГДЕ fkObjectId = @ p0; @ p0 = 5 [Тип: Int32 (0)]
DEBUG NHibernate.SQL [(null)] - ВСТАВИТЬ INTO ObjectFields (fkObjectId,fkFieldId) VALUES (@ p0, @ p1); @ p0 = 5 [Тип: Int32 (0)], @ p1 = 1 [Тип: Int32 (0)]
ОТЛАДКА NHibernate.SQL [(null)] - INSERTINTO ObjectFields (fkObjectId, fkFieldId) ЗНАЧЕНИЯ (@ p0, @ p1); @ p0 = 5 [Тип: Int32 (0)], @ p1 = 2 [Тип: Int32 (0)]

Как вы можетевидите, он выдает операторы delete и затем вставляет заново.

Есть идеи, как это предотвратить?

Ответы [ 2 ]

4 голосов
/ 01 декабря 2010

Короче говоря, сумки ведут себя так, что вы должны использовать другой тип коллекции.Здесь у вас есть хорошее объяснение из документа NHibernate, но я рекомендую вам прочитать всю главу ( 17.5. Понимание производительности коллекций

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

Наборы имеют первичный ключ, состоящий из столбцов ключей и элементов, что может быть менее эффективным для некоторых типов элементов коллекции, в частности для составных элементов или больших текстовых или двоичных полей: база данных может быть не в состоянии эффективно индексировать сложный первичный ключ.с другой стороны, для одного-многих или многих-многих ассоциаций, особенно в случае синтетических идентификаторов, он, вероятно, будет столь же эффективным. (Примечание: если вы хотите, чтобы SchemaExport фактически создавал первичный ключ набора длявы,Вы должны объявить все столбцы как not-null = "true".)

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

Сумки - худший случай.Поскольку пакет допускает повторяющиеся значения элементов и не имеет индексного столбца, первичный ключ не может быть определен.NHibernate не имеет возможности различать дубликаты строк.NHibernate решает эту проблему путем полного удаления (в одном DELETE) и воссоздания коллекции при каждом ее изменении.Это может быть очень неэффективно.

0 голосов
/ 04 декабря 2010

Я обнаружил, что в моей ситуации сумка с идентификацией работала лучше, но другой ответ от Клаудио был хорошим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...