2008-10-17 30 views
14

Tengo un escenario en un sistema que he tratado de simplificar lo mejor que puedo. Tenemos una tabla de artefactos (le permite llamar), se puede acceder a los artefactos por cualquier cantidad de roles de seguridad y los roles de seguridad pueden acceder a cualquier cantidad 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 la identificación del artefacto con la Identificación del rol.Eliminar muchos en cascada muchos en NHibernate

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

Como tal, el mapeo nhibernate para 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 de manera adecuada y se eliminan todas las referencias entre el artefacto eliminado y papeles (el papel no se elimina, sin embargo, correctamente - como don no quiero que los huérfanos sean eliminados).

El problema es cómo eliminar una función y hacer que aclare la tabla de asociación automáticamente. Si actualmente intento eliminar una función, obtengo una restricción de referencia ya que todavía hay entradas en la tabla de asociación para la función. La única forma de eliminar un rol con éxito es consultar todos los artefactos que se vinculen 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 o agradable, especialmente cuando se encuentra en el sistema simplificado, los roles pueden asociarse con cualquier cantidad de otras tablas/objetos.

Necesito poder indicarle a NHibernate que quiero que se despeje esta tabla de asociación cada vez que elimino una función, ¿es posible ?, y si es así, ¿cómo lo hago?

Gracias por cualquier ayuda.

Respuesta

8

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

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

Roles:

<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 se puede hacer que las propiedades RolesToAccess protegidos para que no contaminan el modelo.

+1

Hola, en su solución, ¿tiene que crear tres clases Role, RolesToAccess y Access? ¿Conoces una solución con solo dos clases Role and Access? –

0

Puede hacer una asignación para la tabla de asociación, y luego invocar eliminar en esa tabla donde 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.

+0

No me gustaría que la tabla de asociación se represente en el modelo de dominio y esta sería la única forma de eliminar manualmente en contra de la tabla de asociación en código utilizando NHibernate. –

0

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

Pero le recomiendo que use esto como último recurso.

0

Debe crear una asignación desde Rol a Artifact.

Puede hacer que la carga sea lenta y asignarla a un miembro virtual protegido, de modo que nunca se acceda a ella, pero necesita esa asignación allí para que NHibernate sepa que debe eliminar los roles de la tabla ArtefactAccess

+0

David, agregando el rol -> asignación de artefactos aunque no eliminaría los datos de la asociación automáticamente ya que el inverso de ese mapeo posee los datos - es decir: eliminar un rol del artefacto o eliminar un artefacto limpiará la tabla de asociación en lugar del otro camino alrededor. Entonces, al agregar el mapeo, tendría que volver a encontrar todos los artefactos que tienen el rol, eliminar el papel y volver a guardar los artefactos (limpiar la tabla de asociación) y luego eliminar el rol; esto simplemente no me parece eficiente. –

1

lo que usted dice aquí:

La única manera de eliminar correctamente un papel es para consultar todos los artefactos que enlazan con ese papel, retire el papel de la colección de la función del artefacto, actualizar los artefactos y elimine el rol - no muy eficiente o agradable, especialmente cuando en el sistema no simplificado, los roles pueden asociarse con cualquier cantidad de otras tablas/objetos.

No es necesario. Supongamos que no desea asignar la tabla de asociación (convertirlo en un objeto de dominio), pero 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 Rol y Artefacto. Ambos tienen una bolsa para la asociación many-many.

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 se puede ver, los dos extremos tienen inversa = false especificado. La documentación de NHibernate le recomienda elegir un extremo de su asociación como el extremo "inverso", pero nada le impide usar ambos como "extremo controlador". 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 infracción FK porque la tabla de asociación no está actualizada, es verdadera. Pero puede resolver esto simplemente borrando la colección al 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 ' fin. Si esto es un poco confuso, aquí hay un ejemplo de código. Si sólo tiene un extremo en control, por su complejo de eliminar lo que necesita 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 cuando se elimina un papel es algo así como

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

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

+0

Cuando uso ambos como el control final, recibo NHibernate intentando insertar la relación dos veces, una para cada extremo. Resolví este problema cambiando el extremo de control al otro lado. –

Cuestiones relacionadas