Многие ко многим удаляют каскад в NHibernate - PullRequest
14 голосов
/ 17 октября 2008

У меня есть сценарий в системе, который я постарался максимально упростить. У нас есть таблица (давайте назовем их) артефактов, артефакты могут быть доступны любому количеству ролей безопасности, а роли безопасности могут получить доступ к любому количеству артефактов. Таким образом, у нас есть 3 таблицы в базе данных - одна с описанием артефактов, другая с описанием ролей и таблица сопоставления «многие ко многим», связывающая идентификатор артефакта с идентификатором роли.

В отношении домена, у нас есть два класса - один для роли и один для артефакта. класс артефакта имеет свойство 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>

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

Проблема заключается в том, как удалить роль и автоматически очистить таблицу связей. Если я сейчас попытаюсь удалить роль, я получу ограничение ссылки, так как в таблице связей для этой роли еще есть записи. Единственный способ успешно удалить роль - это запросить все артефакты, которые связаны с этой ролью, удалить роль из коллекции ролей артефакта, обновить артефакты и затем удалить роль - не очень эффективно или не очень хорошо, особенно в упрощенная система, роли могут быть связаны с любым количеством других таблиц / объектов.

Мне нужно иметь возможность подсказывать NHibernate, что я хочу, чтобы эта таблица ассоциации очищалась всякий раз, когда я удаляю роль - возможно ли это, и если да - как мне это сделать?

Спасибо за любую помощь.

Ответы [ 5 ]

8 голосов
/ 02 января 2009

Так как я искал этот ответ и нашел эту тему в Google (без ответа), я решил опубликовать свое решение для этого. С тремя таблицами: Role, RolesToAccess (ManyToMany), Access.

Создайте следующие сопоставления: Доступ:

<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, чтобы они не загрязняли вашу модель.

1 голос
/ 12 декабря 2010

Что вы говорите здесь:

Единственный способ успешно удалить роль - это запросить все артефакты, связанные с этой ролью, удалить роль из коллекции ролей артефакта, обновить артефакты и затем удалить роль - не очень эффективно или красиво, особенно когда в В упрощенной системе роли могут быть связаны с любым количеством других таблиц / объектов.

Не обязательно. Предположим, что вы не хотите отображать таблицу ассоциации (сделать ее объектом домена), вы все равно можете выполнять удаление на обоих концах с минимальным кодом.

Допустим, есть 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>

Как видите, на обоих концах указано обратное = false. Документация NHibernate рекомендует вам выбрать один конец вашей ассоциации в качестве «обратного» конца, но ничто не мешает вам использовать оба в качестве «контрольного конца». При выполнении обновлений или вставок это работает в обоих направлениях без помех. При выполнении удалений любого из концов вы получаете ошибку нарушения FK, поскольку таблица ассоциации не обновляется, true. Но вы можете решить эту проблему, просто очистив коллекцию на другом конце, перед выполнением удаления, которое намного менее сложно, чем то, что вы делаете, которое выглядит в «другом» конце ассоциации, если есть варианты использования этого ' конец. Если это немного сбивает с толку, вот пример кода. Если у вас есть только один конец контроля, для сложного удаления вам нужно сделать:

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

Это одна дополнительная строка кода, но таким образом вам не нужно принимать решение о том, какой конец ассоциации является обратным. Вам также не нужно отображать таблицу ассоциации для полного контроля.

0 голосов
/ 18 октября 2008

Хотя я считаю, что NHibernate должен предоставить способ сделать это без наличия коллекции в классе ролей C #, вы всегда можете установить это поведение в SQL. Выберите каскадное удаление для FK в базе данных, и оно должно быть автоматическим, просто следите за кешем NHib.

Но я настоятельно советую вам использовать это как последний ресурс.

0 голосов
/ 18 октября 2008

Вам необходимо создать отображение из роли в Artifact.

Вы можете сделать его лениво загружаемым и сопоставить его с защищенным виртуальным участником, чтобы к нему фактически никогда не обращались, но вам нужно это отображение, чтобы NHibernate знал, что ему нужно удалить роли из ArtefactAccess таблица

0 голосов
/ 17 октября 2008

Вы можете сделать сопоставление для таблицы ассоциации, а затем вызвать delete для этой таблицы, где Role_id - это значение, которое вы собираетесь удалить, и затем выполнить удаление самой роли. Должно быть довольно просто сделать это.

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