2008-10-17 7 views
14

J'ai un scénario dans un système que j'ai essayé de simplifier du mieux que je peux. Nous disposons d'un tableau d'artefacts (appelons-les), d'artefacts accessibles par n'importe quel nombre de rôles de sécurité et de rôles de sécurité pouvant accéder à n'importe quel nombre d'artefacts. En tant que tel, nous avons 3 tables dans la base de données - l'une décrivant les artefacts, l'autre décrivant les rôles et une table d'association many-to-many reliant l'ID de l'artefact à l'ID du rôle.Plusieurs à supprimer cascade dans NHibernate

Domaine, nous avons deux classes - un pour un rôle et un pour un artefact. la classe artefact possède une propriété IList qui renvoie une liste de rôles pouvant y accéder. (Les rôles n'offrent cependant pas de propriété permettant d'obtenir des artefacts accessibles). En tant que tel, le mappage de nhibernate pour artefact contient ce qui suit:

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

Tout cela fonctionne très bien et si je supprime un artefact, la table d'association est nettoyé de façon appropriée et toutes les références entre l'artefact supprimé et les rôles sont supprimés (le rôle n'est pas supprimé cependant, correctement - comme nous don ne veux pas que les orphelins soient supprimés).

Le problème est - comment supprimer un rôle et lui faire effacer la table d'association automatiquement. Si j'essaie actuellement de supprimer un rôle, j'obtiens une contrainte de référence car il y a toujours des entrées dans la table d'association pour le rôle. La seule façon de supprimer un rôle est de rechercher tous les artefacts liés à ce rôle, de supprimer le rôle de la collection de rôles de l'artefact, de mettre à jour les artefacts, puis de supprimer le rôle - pas très efficace ou agréable. système simplifié, les rôles peuvent être associés à un nombre quelconque d'autres tables/objets.

Je dois être en mesure d'indiquer à NHibernate que je veux effacer cette table d'association chaque fois que je supprime un rôle - est-ce possible, et si oui, comment le faire?

Merci pour toute aide.

Répondre

8

Depuis que je cherchais cette réponse et trouvé ce fil sur google (sans réponse) je me suis dit que je posterais ma solution à cela. Avec trois tables: Role, RolesToAccess (ManyToMany), Access.

Créer les applications suivantes: Accès:

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

Rôles:

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

Comme mentionné ci-dessus, vous pouvez rendre les propriétés RolesToAccess protégées afin qu'ils ne polluent pas votre modèle.

+1

Bonjour, dans votre solution, devez-vous créer trois classes Role, RolesToAccess et Access? Connaissez-vous une solution avec seulement deux classes Role and Access? –

0

Vous pouvez effectuer un mappage pour la table d'association, puis appeler delete sur cette table où le Role_id est la valeur que vous êtes sur le point de supprimer, puis effectuer la suppression du rôle lui-même. Devrait être assez simple pour le faire.

+0

Je ne voudrais pas que la table d'association à être représentée dans le modèle de domaine et ce serait le seul moyen de supprimer manuellement sur la table d'association dans le code en utilisant NHibernate. –

0

Bien que je pense que NHibernate doit fournir un moyen de le faire sans avoir la collection dans la classe C# des rôles, vous pouvez toujours définir ce comportement dans SQL. Sélectionnez sur supprimer la cascade pour le FK dans la base de données et il devrait être automatique, faites attention au cache de NHib. Mais je vous conseille fortement de l'utiliser comme une dernière ressource.

0

Vous devez créer un mappage de Rôle à Artifact.

Vous pouvez le charger paresseux et le mapper sur un membre virtuel protégé, afin qu'il ne soit jamais réellement accédé, mais vous avez besoin de ce mappage là pour que NHibernate sache qu'il doit supprimer les rôles de la table ArtefactAccess

+0

David, en ajoutant le rôle -> cartographie artefact mais ne serait pas supprimer les données d'association automatiquement l'inverse de cette cartographie est propriétaire des données - à savoir: la suppression d'un rôle d'artefact, ou la suppression d'un artefact nettoyer la table d'association plutôt que la inverse. Donc, en ajoutant la cartographie, je devrais à nouveau trouver tous les artefacts qui ont le rôle, retirer le rôle et réenregistrer les artefacts (nettoyage de la table d'association), puis supprimer le rôle - cela ne me semble pas efficace. –

1

Ce que vous dites ici:

La seule façon de supprimer avec succès un rôle consiste à interroger tous les objets qui pointent vers ce rôle, supprimer le rôle de la collection de rôle de l'artefact, mettez à jour les objets et supprimer le rôle - pas très efficace ou agréable, surtout quand dans le système non simplifié, les rôles peuvent être associés à un certain nombre d'autres tables/objets.

est pas nécessaire. Supposons que vous ne souhaitiez pas mapper la table d'association (en faire un objet de domaine), vous pouvez toujours effectuer des suppressions aux deux extrémités avec un code minimal.

Disons qu'il ya 3 tables: rôle, des artefacts et ArtifactAccess (la table de liaison). Dans votre mappage, vous ne disposez que d'objets de domaine pour Rôle et Artefact. Les deux ont un sac pour l'association many-many.

Rôle:

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

artefact:

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

Comme vous pouvez le voir, les deux extrémités ont inverse = false spécifié. La documentation de NHibernate vous recommande de choisir une extrémité de votre association comme extrémité «inverse», mais rien ne vous empêche d'utiliser les deux comme «fin de contrôle». Lorsque vous effectuez des mises à jour ou des insertions, cela fonctionne dans les deux sens sans accroc. Lorsque vous effectuez des suppressions de l'une des extrémités, vous obtenez une erreur de violation FK car la table d'association n'est pas mise à jour, true. Mais vous pouvez résoudre ceci en effaçant simplement la collection à l'autre extrémité, avant d'effectuer la suppression, ce qui est beaucoup moins complexe que ce que vous faites, qui regarde dans l'autre extrémité de l'association s'il y a des utilisations de cette ' fin. Si c'est un peu confus, voici un exemple de code. Si vous avez seulement une extrémité dans le contrôle, pour votre complexe, vous supprimez devez faire:

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

Ce que je fais lors de la suppression d'un rôle est quelque chose comme

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

C'est une ligne de code supplémentaire, mais De cette façon, vous n'avez pas besoin de prendre une décision sur la fin de l'association qui est la fin inverse. Vous n'avez également pas besoin de mapper la table d'association pour un contrôle total.

+0

Lorsque j'utilise les deux comme fin de contrôle, j'obtiens NHibernate en essayant d'insérer la relation deux fois, une fois pour chaque extrémité. J'ai résolu ce problème en changeant l'extrémité de contrôle de l'autre côté. –

Questions connexes