Pregunta

Tengo un escenario en un sistema que he intentado simplificar lo mejor que puedo. Tenemos una tabla de (llamémoslos) artefactos, los artefactos pueden ser accedidos por cualquier número de roles de seguridad y los roles de seguridad pueden acceder a cualquier número de artefactos. Como tal, tenemos 3 tablas en la base de datos: una que describe artefactos, una que describe roles y una tabla de asociación de muchos a muchos que vincula el ID de artefacto con el ID de rol.

En cuanto al dominio, tenemos dos clases: una para un rol y otra para un artefacto. La clase de artefacto tiene una propiedad IList que devuelve una lista de roles que pueden acceder a ella. (Sin embargo, los roles no ofrecen una propiedad para obtener artefactos a los que se puede acceder).

Como tal, el mapeo nhibernate para el artefacto contiene lo siguiente;

<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>

Todo esto funciona bien y si elimino un artefacto, la tabla de asociación se limpia adecuadamente y todas las referencias entre el artefacto y los roles eliminados se eliminan (el rol no se elimina, correctamente, ya que no queremos huérfanos eliminado).

El problema es: cómo eliminar una función y hacer que la tabla de asociación se borre automáticamente. Si actualmente trato de eliminar un rol, obtengo una restricción de referencia ya que todavía hay entradas en la tabla de asociación para el rol. La única forma de eliminar con éxito un rol es consultar todos los artefactos que se vinculan con ese rol, eliminar el rol de la colección de roles del artefacto, actualizar los artefactos y luego eliminar el rol, no muy eficiente ni agradable, especialmente cuando en la En el sistema simplificado, los roles se pueden asociar con cualquier número de otras tablas / objetos.

Necesito poder insinuar a NHibernate que quiero que esta tabla de asociación se borre cada vez que elimine un rol. ¿Es esto posible? Si es así, ¿cómo lo hago?

Gracias por cualquier ayuda.

¿Fue útil?

Solución

Desde que estaba buscando esta respuesta y encontré este hilo en google (sin una respuesta) pensé que publicaría mi solución a esto. Con tres tablas: Role, RolesToAccess (ManyToMany), Access.

Crea las siguientes asignaciones: Acceso:

<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>

Funciones:

<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>

Como se mencionó anteriormente, puede hacer que las propiedades de RolesToAccess estén protegidas para que no contaminen su modelo.

Otros consejos

Lo que dices aquí:

  

La única forma de eliminar con éxito un rol es consultar todos los artefactos que enlazan con ese rol, eliminar el rol de la colección de roles del artefacto, actualizar los artefactos y luego eliminar el rol, no muy eficiente ni agradable, especialmente cuando En el sistema no simplificado, los roles pueden asociarse con cualquier número de otras tablas / objetos.

No es necesario. Supongamos que no desea asignar la tabla de asociación (que sea un objeto de dominio), aún puede realizar eliminaciones en ambos extremos con un código mínimo.

Digamos que hay 3 tablas: Role, Artifact y ArtifactAccess (la tabla de enlaces). En su asignación, solo tiene objetos de dominio para Función y Artefacto. Ambos tienen una bolsa para la asociación de muchos, muchos.

Rol:

    <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>

Artefacto:

    <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>

Como puede ver, ambos extremos tienen inverso = falso especificado. La documentación de NHibernate recomienda que elija un extremo de su asociación como el extremo "inverso", pero nada le impide utilizar ambos como "extremo de control". Al realizar actualizaciones o inserciones, esto funciona desde ambas direcciones sin ningún problema. Al realizar eliminaciones de cualquiera de los extremos, se obtiene un error de violación de FK porque la tabla de asociación no está actualizada, es cierto. Pero puede resolver esto simplemente limpiando la colección hacia el otro extremo, antes de realizar la eliminación, que es mucho menos compleja que lo que hace, que está buscando en el "otro" extremo de la asociación si hay usos de "esto". ' final. Si esto es un poco confuso, aquí hay un ejemplo de código. Si solo tiene un extremo en control, para su eliminación compleja debe hacer:

foreach(var artifact in role.Artifacts)
    foreach(var role in artifact.Roles)
        if(role == roleToDelete)
            artifact.Roles.Remove(role)
    artifact.Save();
roleToDelete.Delete();

Lo que hago al eliminar un rol es algo así como

roleToDelete.Artifacts.Clear(); //removes the association record
roleToDelete.Delete(); // removes the artifact record

Es una línea de código adicional, pero de esta manera no es necesario tomar una decisión sobre qué extremo de la asociación es el final inverso. Tampoco es necesario asignar la tabla de asociación para un control total.

Podría hacer una asignación para la tabla de asociación, y luego llamar a delete en esa tabla donde el Role_id es el valor que está a punto de eliminar, y luego realizar la eliminación del rol en sí. Debería ser bastante sencillo hacer esto.

Aunque creo que NHibernate debe proporcionar una manera de hacer esto sin tener la colección en la clase de roles C #, siempre puede establecer este comportamiento en SQL. Seleccione la eliminación en cascada para el FK en la base de datos y debería ser automática, solo tenga cuidado con el caché de NHib.

Pero le recomiendo encarecidamente que use esto como último recurso.

Es necesario crear una asignación de Rol a Artifact .

Puede hacer que se cargue lentamente y asignarlo a un miembro virtual protegido, de modo que nunca se pueda acceder a él, pero necesita esa asignación para que NHibernate sepa que debe eliminar los roles del ArtefactAccess table

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top