Domanda

Ho uno scenario in un sistema che ho cercato di semplificare al meglio. Abbiamo una tabella di artefatti (chiamiamoli), artefatti accessibili da qualsiasi numero di ruoli di sicurezza e ruoli di sicurezza possono accedere a qualsiasi numero di artefatti. Pertanto, abbiamo 3 tabelle nel database: una che descrive gli artefatti, una che descrive i ruoli e una tabella di associazione molti-a-molti che collega l'ID artefatto all'ID ruolo.

Per quanto riguarda il dominio, abbiamo due classi: una per un ruolo e una per un manufatto. la classe artefatto ha una proprietà IList che restituisce un elenco di ruoli che possono accedervi. (I ruoli tuttavia non offrono una proprietà per ottenere artefatti a cui è possibile accedere).

In quanto tale, la mappatura proibitiva per l'artefatto contiene quanto segue;

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

Tutto funziona benissimo e se elimino un artefatto, la tabella dell'associazione viene ripulita in modo appropriato e tutti i riferimenti tra l'artefatto rimosso e i ruoli vengono rimossi (il ruolo non viene eliminato, tuttavia correttamente, poiché non vogliamo orfani cancellato).

Il problema è: come eliminare un ruolo e chiarire automaticamente la tabella delle associazioni. Se attualmente provo a eliminare un ruolo, ottengo un vincolo di riferimento in quanto vi sono ancora voci nella tabella delle associazioni per il ruolo. L'unico modo per eliminare correttamente un ruolo è eseguire una query per tutti i manufatti che si collegano a quel ruolo, rimuovere il ruolo dalla raccolta ruoli del manufatto, aggiornare i manufatti e quindi eliminare il ruolo - non molto efficiente o piacevole, specialmente quando in sistema semplificato, i ruoli possono essere associati a qualsiasi numero di altre tabelle / oggetti.

Devo essere in grado di suggerire a NHibernate che desidero cancellare questa tabella di associazione ogni volta che elimino un ruolo - è possibile, e in tal caso - come posso farlo?

Grazie per l'aiuto.

È stato utile?

Soluzione

Dato che stavo cercando questa risposta e ho trovato questa discussione su Google (senza una risposta) ho pensato di pubblicare la mia soluzione. Con tre tabelle: Ruolo, RolesToAccess (ManyToMany), Accesso.

Crea i seguenti mapping: Accesso:

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

Ruoli:

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

Come accennato in precedenza, puoi proteggere le proprietà RolesToAccess in modo che non inquinino il tuo modello.

Altri suggerimenti

Quello che dici qui:

  

L'unico modo per eliminare correttamente un ruolo è eseguire una query per tutti i manufatti che si collegano a quel ruolo, rimuovere il ruolo dalla raccolta ruoli del manufatto, aggiornare i manufatti e quindi eliminare il ruolo - non molto efficiente o piacevole, specialmente quando in il sistema non semplificato, i ruoli possono essere associati a qualsiasi numero di altre tabelle / oggetti.

Non è necessario. Supponiamo di non voler mappare la tabella delle associazioni (rendendola un oggetto dominio), puoi comunque eseguire le eliminazioni su entrambe le estremità con un codice minimo.

Supponiamo che ci siano 3 tabelle: Role, Artifact e ArtifactAccess (la tabella dei collegamenti). Nella tua mappatura, hai solo oggetti di dominio per Ruolo e Artefatto. Entrambi hanno una borsa per l'associazione molti-molti.

Ruolo:

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

Artefatto:

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

Come puoi vedere, entrambe le estremità hanno inverse = false specificato. La documentazione di NHibernate ti consiglia di scegliere un'estremità dell'associazione come estremità "inversa", ma nulla ti impedisce di utilizzare entrambe come "estremità di controllo". Quando si eseguono aggiornamenti o inserimenti, questo funziona da entrambe le direzioni senza intoppi. Quando si eseguono eliminazioni di una delle estremità, viene visualizzato un errore di violazione FK perché la tabella di associazione non viene aggiornata, vero. Ma puoi risolverlo semplicemente cancellando la raccolta dall'altra parte, prima di eseguire l'eliminazione, che è molto meno complessa di quello che fai, che sta cercando nell'altra estremità dell'associazione se ci sono usi di questo ' fine. Se questo è un po 'confuso, ecco un esempio di codice. Se hai solo un'estremità in controllo, per la tua complessa eliminazione devi fare:

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

Quello che faccio quando cancello un ruolo è qualcosa di simile

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

È un'ulteriore riga di codice, ma in questo modo non è necessario prendere una decisione su quale estremità dell'associazione sia la parte inversa. Inoltre, non è necessario mappare la tabella delle associazioni per il controllo completo.

È possibile creare un mapping per la tabella di associazione, quindi chiamare delete su quella tabella in cui Role_id è il valore che si sta per eliminare, quindi eseguire l'eliminazione del ruolo stesso. Dovrebbe essere abbastanza semplice farlo.

Anche se credo che NHibernate debba fornire un modo per farlo senza avere la raccolta nella classe ruoli C #, è sempre possibile impostare questo comportamento in SQL. Seleziona su eliminazione in cascata per l'FK nel database e dovrebbe essere automatico, fai attenzione alla cache di NHib.

Ma ti consiglio caldamente di usarlo come ultima risorsa.

Devi creare una mappatura da Role a Artefatto .

Puoi renderlo a caricamento lento e mapparlo a un membro virtuale protetto, in modo che non possa mai effettivamente accedervi, ma è necessario quel mapping lì per NHibernate per sapere che deve eliminare i ruoli dal ArtefactAccess table

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top