Плавное nhibernate - сопоставление отношений много-ко-многим на одном объекте
У меня возникла проблема с поиском отношения "многие ко многим", где обе стороны отношения ссылаются на одну и ту же сущность. Я использую Fluent NHibernate и NH3.1.
В принципе, сценарий таков: у меня есть категория, которая может иметь несколько родителей. Таким образом, категория имеет несколько других категорий в качестве родителей, а также несколько других категорий в качестве своих детей.
HasManyToMany(x => x.ParentCategories).AsBag().Table("parentcategorychildren").ParentKeyColumn("ChildID").ChildKeyColumn("ParentID").Cascade.SaveUpdate();
HasManyToMany(x => x.ChildrenCategories).AsBag().Table("parentcategorychildren").ParentKeyColumn("ParentID").ChildKeyColumn("ChildID").Inverse();
Однако, когда я пытаюсь создать factory, я получаю следующую ошибку:
Отношения Category.ChildrenCategories с Category.ChildrenCategories имеют Инверс, указанный с обеих сторон. Удалите обратную сторону с одной стороны отношения.
То, что я нахожу странным, это то, почему он упоминает "Category.ChildrenCategories" в Category.ChildrenCategories, в отличие от ParentCategories?
Любая помощь будет принята с благодарностью!
Я просто создал щедрость для этого, потому что это достаточно важно для меня. Пожалуйста, меня не интересует "вы не можете сделать это" в качестве ответа.
Ответы
Ответ 1
Скорее всего, это ошибка FNH, и она, скорее всего, уже исправлена в последнем исходном коде FNH . Нет проблем при использовании FNH1.0 и NH2.1. Эквивалентное картирование HBM хорошо работает в FNH1.2 и NH3.1:
<bag name="ParentCategories" cascade="all" table="parentcategorychildren">
<key column="ChildID" />
<many-to-many column="ParentID" class="Category" />
</bag>
<bag name="ChildrenCategories" inverse="true" table="parentcategorychildren">
<key column="ParentID" />
<many-to-many column="ChildID" class="Category" />
</bag>
EDIT:
После копания в исходном коде FNH я нашел обходное решение. Скажем, ваша конфигурация выглядит так:
.Mappings(m => {
m.FluentMappings.AddFromAssemblyOf<Category>();
})
Несчастливый код может быть подавлен этой конфигурацией:
.Mappings(m => {
var persistenceModel = new PersistenceModel();
persistenceModel.AddMappingsFromAssembly(typeof(Category).Assembly);
persistenceModel.ValidationEnabled = false; // this makes the trick
m.UsePersistenceModel(persistenceModel);
})
Ответ 2
Это проблема с Fluent NHibernate 2.1 валидации/спаривания отношений. FNH соединяет отношения, а затем проверяет, что только одна сторона отношения имеет .Inverse()
. Поскольку обе ссылки (родительский/дочерний) относятся к одному классу, они являются совпадениями кандидатов при спаривании. В этом случае FNH совпадает с подобием имени. Следовательно, каждый из них соединяется с собой, а не друг с другом. Таким образом, размещение .Inverse()
на одном из них вызывает проверку (обе стороны пары - это те же отношения, которые являются обратными).
Следует исправить это, используя метод OverrideBiDirectionalManyToManyPairing()
на FluentMappingsContainer. Теоретически это позволит вам явно связать дочерние и родительские отношения. Однако в FNH 2.1 есть ошибка, и обратный вызов override никогда не вызывается. (Значение обратного вызова захватывается, прежде чем оно будет установлено с помощью метода).
Как работа, вы можете отключить все проверки в FNH. Существуют только две проверки. Во-первых, что обе стороны отношений не имеют .Inverse()
. Во-вторых, что идентификатор отображается на каждом объекте. Самый чистый способ обнаружения проверки:
.Mappings(m => {
var persistenceModel = new PersistenceModel() { ValidationEnabled = false };
m.UsePersistenceModel(persistenceModel)
.FluentMappings.AddFromAssemblyOf<Category>();
})
Этот подход позволяет отключить проверку, но при этом использовать полную выразительность конфигурации FluentMappings
.
Ответ 3
Да, мне показалось, что это скорее всего ошибка в FNH, так как я пробовал его напрямую с NHibernate без использования Fluent NH, и это сработало. Однако, поскольку я уже установил систему с использованием FNH, я не мог просто вернуться, чтобы не использовать ее.
То, что я сделал, было создано мной как "класс-в-середине" для отношения "многие ко многим", которое обычно генерируется автоматически. Я создал страницу ContentPage_ChildLink
, которая связывает категории Parents
и Children
. Это позволило мне работать с FNH и решить проблему:)
В основном это ContentPage_ChildLink
имеет два поля: ChildID
и ParentID
. Я мог бы установить отношения "Обратный" отдельно, без каких-либо проблем.
Проблема с FNH, по-видимому, заключалась в том, что у вас есть отношения "многие ко многим", обе стороны которых являются одним и тем же классом, единственный случай, который я могу представить, это структура иерархии, которая позволяет нескольким родителям.