7

nella mia applicazione ASP.NET MVC Ho separato il modello di dominio dal modello di visualizzazione.
Trasformo la mia entità in un oggetto viewmodel in modo che possa "alimentare" le mie viste con solo i dati necessari (ho usato valueinjecter per questo scopo).
Durante il processo di salvataggio, il mio controller recupera l'oggetto viewmodel, lo trasforma in un'entità modello di dominio e tenta di mantenerlo con SaveOrUpdate. Ho notato che se provo ad aggiornare un record esistente, Nhibere lo considera come un nuovo oggetto e forza un INSERIMENTO, anche se la mia entità ha un ID appropriato.
Non ho caricato (Get/Load) l'entità prima della causa, vorrei evitare di ri-mappare nuovamente tutti i campi.
C'è qualcosa che sto facendo male? Qual è il modo migliore per farlo?Devo caricare/ottenere un'entità prima di SaveOrUpdate in Nhibernate?

***** - AGGIORNAMENTO - ***

mio controller riceve un utente (ViewModel), lo convalida e cerca di salvarla attraverso un livello di servizio come entità:

public ActionResult Edit(Guid id, Models.User User) 
{ 
... 
var user = new Domain.User(); 
user.InjectFrom(User); 
user.SetId(id); 

user = this._SecurityService.SaveUser(user); 

} 

Questo è il servizio:

public Domain.User SaveUser(Domain.User User) 
     { 
      bool Result = false; 

      if (this._ValidationEngine.IsValid(User)) 
      { 
       using (_UnitOfWork) 
       { 
        if (User.Code != Guid.Empty) 
        { 
         var user = this._UserRepository.Load(User.Code); 
         user.InjectFrom(User); 
         User = this._UserRepository.Update(user); 
        } 
        else { 
         User = this._UserRepository.Save(User); 
        } 
        Result = _UnitOfWork.Commit(); 
       } 
      } 
      return (User); 
     } 

Ho una preoccupazione per il fatto che devo trasformare il mio viewmodel/entità così tante volte. Ora, quando provo a salvare un nuovo utente, ho ricevuto questo messaggio: La riga è stata aggiornata o eliminata da un'altra transazione (o la mappatura dei valori non salvati era errata)
Probabilmente questo è in qualche modo correlato a ciò che Darin mi stava dicendo.
Ci sono modi migliori per fare ciò che sto cercando di fare?

UPDATE

ho notato che l'errore "Riga è stato aggiornato o eliminato ..." è causato dal fatto che ho una versione definita per le mie mappature. Quello che posso capire è che ho bisogno di avere l' e la versione corrispondente all'entità che voglio aggiornare.
Mi piacerebbe capire come gli altri fanno queste cose con DDD + ASP.NET MVC + NHibernate ???

SOLUZIONE

Tutti i miei soggetti sono una versione definita (ho dimenticato di dire, mi spiace):

<version name="Version" type="System.Int32" unsaved-value="0"> 
    <column name="Version" not-null="true" /> 
</version> 

Come Ayende spiegato here, NHibernate tenta di aggiornare la mia entità con una query come questa :

UPDATE Table SET field1 = 'bla', Version = (y+1) WHERE id = x AND Version = y 

dove dovrebbe essere la versione della mia entità. Poiché non stavo popolando la mia entità con una versione, genererebbe un'eccezione StaleObjectException.
Ho aggiunto un campo versione al mio viewmodel. L'ho salvato in un campo nascosto della mia vista insieme all'ID.
Il mio controller ora riceve un viewmodel con un ID e una versione. ho iniettare questi campi nella mia entità del dominio e lasciare che il repository salvarlo (non mi ricarico la mia entità):

User = this._UserRepository.Update(user); 

Se ho uno StaleObjectException un'eccezione significa che qualcun altro ha aggiornato la riga DB e fornirò all'utente un feedback.

+0

prova a caricare l'entità e dopo re-mapparla (so che non lo vuoi in questo modo), prova questo e dicci se funziona in questo modo – Omu

+0

Immagino che il mio problema sia con la versione.Io ottenuto definito nella mia mappatura. per trovare un modo migliore per farlo: – LeftyX

risposta

0

Dato che si dispone già di un ID e, pertanto, sappiamo che questo è un aggiornamento, utilizzare session.Update anziché SaveOrUpdate.

+0

Temo di non poterlo fare se cerco di salvare la mia entità ottengo questo messaggio: un oggetto diverso con lo stesso valore identificativo era già associato alla sessione: caedb8a4-abce-4c6f-b171-9e7200cc7a37, di entità : BpReminders.Domain.User – LeftyX

+0

Ciò significa che l'oggetto è già stato caricato. Perché non stai aggiornando l'oggetto già caricato allora? –

+0

scusa è stato un errore. Quello che sto facendo ora è caricare un'entità dal repository e fonderla con quella ottenuta dal controller. Ricevo ancora un errore "La riga è stata aggiornata o cancellata da un'altra transazione (o la mappatura dei valori non salvati era errata)" quando provo a inserire. Aggiornerò la mia domanda originale con ulteriori informazioni. – LeftyX

4

Per SaveOrUpdate funzionare come previsto, è necessario specificare esplicitamente l'attributo unsaved-value nella mappatura <id>. Così, per esempio si avrebbe:

<id unsaved-value="0" ... 

e quindi emettere una chiamata SaveOrUpdate su un modello che ha la proprietà ID assegnato ad un valore diverso da 0 e che sta per UPDATE invece di INSERT. Quindi, per rispondere alla tua domanda, no, non è necessario emettere manualmente un numero SELECT prima di UPDATE. SaveOrUpdate dovrebbe fare questo dietro le quinte.

+0

Grazie Daring. Suppongo di dover usare un Guid vuoto (00000000-0000-0000-0000-000000000000) se il mio id è di tipo Guid, vero? – LeftyX

+0

@vandalo, prova questo: 'unsaved-value =" 00000000-0000-0000-0000-000000000000 "' (non testato) –

+0

Grazie, ancora. Cosa faresti, comunque? Dovrei piuttosto caricare l'entità dal DB e compilare ogni campo con la nuova entità in ca se sto cercando di aggiornare? Ci sono delle buone pratiche? Grazie ancora per il vostro aiuto. – LeftyX