Domanda

Quando utilizzo Rhino Commons UnitOfWork (in una UnitOfWorkApplication per ASP-MVC), mi piace utilizzare la classe statica del repository Rhino per salvare entità come questa:

Repository<Car>.Save(new Car(Id = 1));

Trovo che posso quindi far uscire l'entità immediatamente dopo quella chiamata utilizzando:

Car car = Repository<Car>.Get(1);

Funziona bene.Tuttavia, quando utilizzo il provider NHibernate Linq su Rhino UnitOfWork in questo modo:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()
               select rep).ToList();

Ottengo una lista vuota.Sembra che debba chiamare UnitOfWork.Current.Flush() prima di poter far uscire la macchina in questo modo.Non capisco perché, dato che dietro le quinte presumo che entrambi i metodi di recupero stiano interrogando la stessa sessione/unità di lavoro.Ciò significa che dovresti chiamare UnitOfWork.Current.Flush() dopo ogni salvataggio nel database?NHibernate non dovrebbe essere in grado di capire quando svuotarsi?Oppure sto fraintendendo qualcosa?

È stato utile?

Soluzione

Ok, sembra che sebbene una chiamata Get al repository possa utilizzare la cache della sessione, quindi è possibile "vedere" l'auto salvata nella cache:

Car car = Repository<Car>.Get(1); // This works because it uses the same session

Una query linq NON utilizza la cache di sessione:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()               
select rep).ToList(); // Does not work, even if it is in the same code block and even though it uses the same session

Quindi la migliore pratica è che qualsiasi modifica al database (salvataggio, aggiornamento, eliminazione, inserimento) dovrebbe essere seguita da:

UnitOfWork.Session.Flush(), 

o avvolto in un:

With.Transaction(delegate{
   // code here
})

oppure decora il tuo metodo con [Transazione] e usa ATM.Ciò garantirà che le query linq successive esamineranno dati aggiornati.

Altri suggerimenti

Quando si chiama Repository.Save, si notifica alla sessione gestita dal repository di tenere traccia di tale oggetto e sincronizzare le modifiche al database al prossimo flush. Fino a quando non si scarica la sessione, non vengono apportate modifiche al database. L'oggetto diventa parte della cache della sessione e quindi verrà restituito da Get (1).

Quando si esegue una query per popolare una raccolta, la sessione richiede al database di ottenere i risultati, a meno che non abbia già memorizzato nella cache quei risultati. Dato che non hai ancora aggiornato il database, l'auto che hai aggiunto alla sessione non farà parte del set di risultati. (< - Forse errato) Se sto leggendo la documentazione correttamente, sia i risultati della query che le entità Save () ed dovrebbero essere aggiunti alla cache della sessione (di primo livello). Ciò non significa necessariamente che il querystatement.List() interroghi la cache dopo aver aggiunto i risultati del DB ... Sto facendo fatica a girare la testa esattamente cosa sta succedendo.

A parte questo, credo che tu possa impostare la sessione su autoflush ma dovrei controllare la documentazione.

AGGIORNAMENTO:

Penso che potrei vedere cosa sta succedendo qui. La sessione predefinita FlushMode è Auto ma Rhino UnitOfWork.Start() crea una sessione con Commit impostato su Flush(), il che significa che la sessione non si scaricherà automaticamente a meno che non si chiami esplicitamente FlushMode = Auto o si esegua il commit della transazione. Con Session.Find di UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto;, NHibernate (a volte?) Svuota la sessione prima di eseguire una query per impedire la restituzione di dati non aggiornati. Se ho ragione, la tua transazione DB è simile a:

SELECT * FROM Car

INSERT INTO Car (...) VALUES (...)

Quando lo scarico automatico sembra un po 'ambiguo dalla documentazione / blog che ho letto ... la risposta più comune è che con <=> scarica " a volte " sebbene garantisca che <=> non restituirà mai dati non aggiornati. Dal momento che NHibernate Linq in realtà crea una query Criteria, potrebbe non innescare lo scaricamento automatico (forse questo è stato corretto ora ... è difficile da sapere).

Quindi mi sembra che nel tuo caso tu voglia svuotare dopo il tuo salvataggio perché vuoi immediatamente recuperare i risultati del tuo salvataggio. In un'unità di lavoro più piccola in cui si aggiornavano solo entità, un singolo Commit () andava bene. Forse <=> farebbe il trucco, ma il fatto che UOW Factory imposti esplicitamente la modalità su Commit sembra incoraggiarti a pensare davvero ai tuoi confini UOW.

Grazie a Stuart Childs, sospetto che abbia ragione sul fatto che il problema potrebbe riguardare il provider NHibernate Linq. Non sono sicuro di cosa faccia dietro le quinte ma potrebbe usare una sessione diversa, in tal caso ha senso che devo svuotare il salvataggio del repository prima che la query Linq lo "veda". È tempo di consultare il codice sorgente, ma mi è stato detto che mi scioglierà la testa nel tentativo di capirlo!

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