2009-05-31 2 views
6

ho seguente modello:Elimina tiri "oggetto eliminato sarebbe ri-salvato da cascata"

<class name="Person" table="Person" optimistic-lock="version"> 
    <id name="Id" type="Int32" unsaved-value="0"> 
    <generator class="native" /> 
    </id> 
    <!-- plus some properties here --> 
</class> 

<class name="Event" table="Event" optimistic-lock="version"> 
    <id name="Id" type="Int32" unsaved-value="0"> 
    <generator class="native" /> 
    </id> 
    <!-- plus some properties here --> 
</class> 

<class name="PersonEventRegistration" table="PersonEventRegistration" optimistic-lock="version"> 
    <id name="Id" type="Int32" unsaved-value="0"> 
    <generator class="native" /> 
    </id> 
    <property name="IsComplete" type="Boolean" not-null="true" /> 
    <property name="RegistrationDate" type="DateTime" not-null="true" /> 
    <many-to-one name="Person" class="Person" column="PersonId" foreign-key="FK_PersonEvent_PersonId" cascade="all-delete-orphan" /> 
    <many-to-one name="Event" class="Event" column="EventId" foreign-key="FK_PersonEvent_EventId" cascade="all-delete-orphan" /> 
</class> 

ci sono immobili indicando PersonEventRegistration di persona né in evento.

Quando provo ad eliminare una voce dalla PersonEventRegistration, ottengo il seguente errore:

"deleted object would be re-saved by cascade" 

Il problema è che non si deve conservare questo oggetto in qualsiasi altra raccolta - il codice di eliminazione è simile al seguente:

public bool UnregisterFromEvent(Person person, Event entry) 
{ 
    var registrationEntry = this.session 
     .CreateCriteria<PersonEventRegistration>() 
     .Add(Restrictions.Eq("Person", person)) 
     .Add(Restrictions.Eq("Event", entry)) 
     .Add(Restrictions.Eq("IsComplete", false)) 
     .UniqueResult<PersonEventRegistration>(); 

    bool result = false; 
    if (null != registrationEntry) 
    { 
     using (ITransaction tx = this.session.BeginTransaction()) 
     { 
      this.session.Delete(registrationEntry); 
      tx.Commit(); 
      result = true; 
     } 
    } 
    return result; 
} 

Cosa sto facendo di sbagliato qui?

risposta

3

Per quanto ne so, cascade="all-delete-orphan" appartiene all'elemento di mappatura raccolta, non lo many-to-one. Non hai mostrato le altre due parti della tua mappatura quindi non posso dirlo con certezza, ma questo è possibile (probabilmente) il problema.

Penso Person dovrebbe essere simile:

<!-- other properties --> 
<set name="Events" inverse="true" cascade="all-delete-orphan"> 
    <key column="Person_id" /> 
    <one-to-many class="PersonEventRegistration" /> 
</set> 

Event:

<!-- similar mapping for Event --> 

PersonEventRegistration:

<!-- other properties --> 
<many-to-one name="Person" class="Person" column="PersonId" foreign-key="FK_PersonEvent_PersonId" cascade="delete" <!-- or many ="all" ? --> /> 

In realtà, quanto sopra potrebbe essere cascate conflittuali (che potrebbe essere quello che hai). Quindi, in realtà, la mia risposta è due cose:

  1. cascade="all-delete-orphan" non ha alcun significato in many-to-one.
  2. Assicurati di aver davvero pensato, attraverso come stai lavorando con le tue entità e come dovrebbero far convergere le loro operazioni.
+0

non ho notato che il post non conteneva tutta la formattazione ... in ogni caso - l'evento e il mapping alle persone non contengono tutte le informazioni su PersonEventRegistration. questa classe è usata per supportare la mappatura molti-a-molti + alcuni attributi extra (non ho trovato nessun esempio in cui la modalità nhibner avrebbe supportato tale scenario). proverò a cascade = "cancella" comunque. – Greg

+2

I tuoi consigli sono azzeccati. È molto di più che "' all-delete-orphan' non ha significato ". Il trasferimento in cascata di un'eliminazione da un bambino a un genitore è solitamente _evil_. Questo è ciò che 'all' e' all-delete-orphan' farebbero in un 'many-to-one'. Eliminando il 'PersonEventRegistration' con quelle cascate si farebbe in modo che NHibernate tentasse di cancellare anche' Person' e 'Event', il che non è sicuramente quello che intende Greg. Ed è per questo che l'eliminazione fallisce perché la Persona e l'Evento sono ancora referenziati altrove, quindi NHibernate non può cancellarli. –

+0

... quindi la cascata corretta per un 'many-to-one' è in genere' save-update'. –

1

Try de-referenziamento Persona e eventi nella cancellazione:

public bool UnregisterFromEvent(Person person, Event entry) 
    { 
     var registrationEntry = this.session 
      .CreateCriteria<PersonEventRegistration>() 
      .Add(Restrictions.Eq("Person", person)) 
      .Add(Restrictions.Eq("Event", entry)) 
      .Add(Restrictions.Eq("IsComplete", false)) 
      .UniqueResult<PersonEventRegistration>(); 

     bool result = false; 
     if (null != registrationEntry) 
     { 
      using (ITransaction tx = this.session.BeginTransaction()) 
      { 
       registrationEntry.Person = null; 
       registrationEntry.Event = null; 
       this.session.Delete(registrationEntry); 
       tx.Commit(); 
       result = true; 
      } 
     } 
     return result; 
    } 

Inoltre, non ero consapevole del fatto che si potrebbe aggiungere una restrizione su un oggetto, avrei scritto questo utilizzando gli alias e gli ID .

  .Add(Restrictions.Eq("Person", person)) 
      .Add(Restrictions.Eq("Event", entry))