Domanda

Utilizzando NHibernate solito query per singoli record utilizzando il Get () o Load () metodi (a seconda se ho bisogno di un proxy o no):

SomeEntity obj = session.Get<SomeEntity>(new PrimaryKeyId(1));

Ora, se eseguo questa dichiarazione due volte, come nell'esempio qui sotto, vedo solo una query in esecuzione nei miei Unittests:

SomeEntity obj1 = session.Get<SomeEntity>(new PrimaryKeyId(1));
SomeEntity obj2 = session.Get<SomeEntity>(new PrimaryKeyId(1));

Fin qui, tutto bene. Ma ho notato uno strano comportamento quando ottiene lo stesso oggetto utilizzando una query ICriteria. Guarda il mio codice qui sotto: Ho la prima istanza di oggetto. Sono quindi modificare il valore di una proprietà di 10 (il valore nel database è 8), ottenere un altro esempio e infine controllare i valori della seconda istanza di oggetto.

//get the first object instance.
SomeEntity obj1 = session.CreateCriteria(typeof(SomeEntity))
                         .Add(Restrictions.Eq("Id", new PrimaryKeyId(1)))
                         .UniqueResult<SomeEntity>();

//the value in the database and the property is 8 at this point. Let's set it to 10.
obj1.SomeValue = 10;

//get the second object instance.
SomeEntity obj2 = session.CreateCriteria(typeof(SomeEntity))
                         .Add(Restrictions.Eq("Id", new PrimaryKeyId(1)))
                         .UniqueResult<SomeEntity>();

//check if the values match.
Assert.AreEqual(8, obj2.SomeValue);

Ora, per qualche motivo l'asserzione fallisce, perché il valore è 10 di obj2 anche se ho chiesto per l'oggetto con una nuova query. la cosa divertente è, ci sono 2 esattamente le stesse query di selezione viene eseguito in base alla mia finestra di output unit test. La mia domanda: perché c'è 2 domande in corso di esecuzione, se il secondo oggetto prelevato dalla prima cache di livello sono

?

Mi sto perdendo qualcosa o si tratta di un bug?

Saluti, Ted

Modifica # 1: usando NHibernate v2.1.2GA Modifica # 2: ho aggiunto qualche spiegazione in più circa le 2 domande in corso di esecuzione per l'ultimo paragrafo

.
È stato utile?

Soluzione 2

Bene, dopo aver imparato molto di più su NHibernate ora posso rispondere a questa domanda me: I rendimenti di query ICriteria un elenco di oggetti prelevati da NHibernate. NHibernate non sa quali oggetti sono restituiti fino a quando non vengono abbinati ad uno ad uno con l'oggetto nella prima cache di livello. Se l'articolo è già nel primo livello di cache di mappare la voce di leggere dal database viene scartata. se non è nella mappa di identità, l'elemento viene inserito nella prima cache di livello.

Un altro "a-ha!" momento: supponiamo che si esegue la query per la prima volta mentre ci sono 5 righe nel database tutte le righe vengono recuperate e messe in cache di primo livello. ora nel corso del tempo 5 più record vengono aggiunti al tavolo e si esegue nuovamente la query. Ora tutti i 10 record sono inverosimile, ma NHibernate vede 5 di loro sono già nella cache e solo aggiungere i 5 ultimi record. Quindi, in pratica si inverosimile 5 record per nulla (solo per abbinare gli identificatori con gli identificatori di oggetto nella mappa di identità).

Altri suggerimenti

Get / Load usare la cache di 1 ° livello, questo è il motivo per cui non si vede il 2 ° chiamata fuori il db. Le query non utilizzano la cache di 1 ° livello. Tuttavia, è possibile impostare query per utilizzare la cache di 2 ° livello. Vedi dettagli qui

Aggiorna Che cosa è probabile che accada è la query sta facendo un carico di 2 fasi. Così si sta facendo il set di risultati, ma anche controllando la cache di 1 ° livello per vedere se qualche entità esistono lì. Se lo fanno, allora restituisce l'oggetto in cache. Vedere il metodo NHibernate.Loader.Loader.GetRow. Ecco la riga relativa:

//If the object is already loaded, return the loaded one
obj = session.GetEntityUsingInterceptor(key);

Per quanto ne so, solo 'Get' (e forse Load) utilizzare la cache di 1 ° livello.

Utilizzando l'API criteri induce sempre in una query che colpisce il DB, a meno che la cache di 2 ° livello è attivata.

Modifica: ulteriori informazioni possono essere trovate qui

Non so il motivo per cui una seconda query è Ran, ma il comportamento atteso di NHibernate è se chiedete lo stesso oggetto per ID dalla stessa sessione, si ottiene la prima cache di livello.

Nella mia comprensione, quando si utilizza un criteri, si sono fondamentalmente dicendo a NHibernate: "Voglio le righe di filtro basate su espressioni". Se visto in quel modo, NHibernate ha alcun modo di sapere se la query restituisce sempre la stessa riga filtrato (s) dal database, quindi deve interrogare di nuovo.

Inoltre, è possibile utilizzare query nella cache solo con il secondo livello di cache, come da documentazione:

Quindi, la cache delle query deve essere sempre utilizzato in combinazione con la cache di secondo livello.

qui

NHibernate è probabilmente rilascia un aggiornamento tra la prima e la seconda query per proteggere l'utente da un problema di concorrenza. Come Frederik ha sottolineato, è necessario utilizzare sempre Get per recuperare un oggetto dalla sua chiave.

Sono curioso, che cosa è la PrimaryKeyId involucro aggiungendo?

EDIT:

Tuttavia si sta lavorando (i miei soldi è ancora un aggiornamento prima select), questo comportamento è di progettazione. Se si desidera eliminare l'oggetto in memoria e caricare una nuova istanza di esso dalla sessione, quindi Evict l'originale dalla prima sessione. V'è anche un metodo di Refresh si potrebbe provare.

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