Многие для многих удаляют каскад в NHibernate
У меня есть сценарий в системе, который я пытался упростить, насколько это возможно. У нас есть таблица (позволяет называть их) артефакты, к артефактам можно получить доступ к любому числу ролей безопасности, а роли безопасности могут получить доступ к любому количеству артефактов. Таким образом, у нас есть 3 таблицы в базе данных - одна из которых описывает артефакты, описывающие роли и таблицу ассоциаций "многие-ко-многим", связывающую идентификатор артефакта с идентификатором роли.
Домен мудрый, у нас есть два класса: один для роли и один для артефакта. класс artefact имеет свойство IList, которое возвращает список ролей, которые могут получить к нему доступ. (Роли, однако, не предлагают свойства для получения артефактов, к которым можно получить доступ).
Таким образом, отображение nhibernate для артефакта содержит следующее:
<bag name="AccessRoles" table="ArtefactAccess" order-by="RoleID"
lazy="true" access="field.camelcase-underscore" optimistic-lock="false">
<key column="ArtefactID"/>
<many-to-many class="Role" column="RoleID"/>
</bag>
Все это прекрасно работает, и если я удалю артефакт, таблица ассоциаций будет очищена соответствующим образом, и все ссылки между удаленным артефактом и ролями будут удалены (роль не удалена, хотя, правильно - поскольку мы не хотим, чтобы сироты удален).
Проблема заключается в том, как удалить роль и автоматически очистить таблицу ассоциаций. Если в настоящее время я пытаюсь удалить роль, я получаю ссылочное ограничение, поскольку в таблице сопоставления для роли все еще есть записи. Единственный способ успешно удалить роль - это запрос для всех артефактов, которые ссылаются на эту роль, удалить роль из коллекции ролей artefact, обновить артефакты, а затем удалить роль - не очень эффективную или приятную, особенно когда в un- упрощенная система, роли могут быть связаны с любым количеством других таблиц/объектов.
Мне нужно уметь ссылаться на NHibernate, что я хочу, чтобы эта таблица ассоциаций была очищена всякий раз, когда я удаляю роль - возможно ли это, и если да - как это сделать?
Спасибо за любую помощь.
Ответы
Ответ 1
Поскольку я искал этот ответ и нашел этот поток в google (без ответа), я решил, что опубликую свое решение. С тремя таблицами: роль, RolesToAccess (ManyToMany), доступ.
Создайте следующие сопоставления:
Доступ:
<bag name="Roles" table="RolesToAccess" cascade="none" lazy="false">
<key column="AccessId" />
<many-to-many column="AccessId" class="Domain.Compound,Domain" />
</bag>
<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false">
<key column="AccessId" on-delete="cascade" />
<one-to-many class="Domain.RolesToAccess,Domain" />
</bag>
Роли:
<bag name="Accesses" table="RolesToAccess" cascade="none" lazy="false">
<key column="RoleId" />
<many-to-many column="RoleId" class="Domain.Compound,Domain" />
</bag>
<bag name="RolesToAccess" cascade="save-update" inverse="true" lazy="false">
<key column="RoleId" on-delete="cascade" />
<one-to-many class="Domain.RolesToAccess,Domain" />
</bag>
Как уже упоминалось выше, вы можете защитить свойства RolesToAccess, чтобы они не загрязняли вашу модель.
Ответ 2
Что вы здесь скажете:
Единственный способ успешно удалить роль - это запрос для всех артефактов, которые ссылаются на эту роль, удалить роль из коллекции ролей artefact, обновить артефакты, а затем удалить роль - не очень эффективно или приятно, особенно когда несложная система, роли могут быть связаны с любым количеством других таблиц/объектов.
Не нужно. Предположим, вы не хотите сопоставлять таблицу ассоциаций (сделать ее объектом домена), вы все равно можете выполнять удаление с обоих концов с минимальным кодом.
Скажем, есть 3 таблицы: Role, Artifact и ArtifactAccess (таблица ссылок).
В вашем сопоставлении у вас есть только объекты домена для роли и артефакта. У обоих есть сумка для ассоциации многих-многих.
Роль:
<bag name="Artifacts" table="[ArtifactAccess]" schema="[Dbo]" lazy="true"
inverse="false" cascade="none" generic="true">
<key column="[ArtifactID]"/>
<many-to-many column="[RoleID]" class="Role" />
</bag>
Артефакт:
<bag name="Roles" table="[ArtifactAccess]" schema="[Dbo]" lazy="true"
inverse="false" cascade="none" generic="true">
<key column="[RoleID]"/>
<many-to-many column="[ArtifactID]" class="Role" />
</bag>
Как вы можете видеть, оба конца имеют inverse = false. Документация NHibernate рекомендует вам выбрать один конец вашей ассоциации как "обратный" конец, но ничто не мешает вам использовать как "контрольный конец". При выполнении обновлений или вставок это работает в обоих направлениях без заминки. При выполнении удалений одного из концов вы получаете ошибку FK-нарушения, потому что таблица ассоциации не обновляется, true. Но вы можете решить эту проблему, просто очистив коллекцию до другого конца, прежде чем выполнять удаление, которое намного сложнее, чем то, что вы делаете, которое ищет в "другом" конце ассоциации, если есть использование 'this' конец. Если это немного запутанно, вот пример кода. Если у вас есть только один конец управления, для вашего сложного удаления вам нужно сделать:
foreach(var artifact in role.Artifacts)
foreach(var role in artifact.Roles)
if(role == roleToDelete)
artifact.Roles.Remove(role)
artifact.Save();
roleToDelete.Delete();
То, что я делаю при удалении роли, похоже на
roleToDelete.Artifacts.Clear(); //removes the association record
roleToDelete.Delete(); // removes the artifact record
Это одна дополнительная строка кода, но таким образом вам не нужно принимать решение о том, какой конец ассоциации является обратным концом. Вам также не нужно сопоставлять таблицу ассоциаций для полного контроля.
Ответ 3
Вы можете сделать сопоставление для таблицы ассоциаций, а затем вызвать delete в этой таблице, где Role_id - это значение, которое вы собираетесь удалить, а затем выполнить удаление самой роли. Должно быть достаточно просто сделать это.
Ответ 4
Хотя я считаю, что NHibernate должен предоставить способ сделать это, не имея коллекции в ролях класса С#, вы всегда можете установить это поведение в SQL. Выберите для каскадного удаления для FK в базе данных, и он должен быть автоматическим, просто следите за кешем NHib.
Но я настоятельно рекомендую вам использовать это как последний ресурс.
Ответ 5
Вам нужно создать сопоставление от Роли до Artifact
.
Вы можете сделать это ленивой загрузкой и сопоставить ее с защищенным виртуальным членом, чтобы к ней никогда не обращались, но вам нужно, чтобы это было NHibernate, чтобы знать, что он должен удалить роли из ArtefactAccess
таблица