O NHibernate ISession Flush:Onde e quando usar, e por quê?
-
09-06-2019 - |
Pergunta
Uma das coisas que me completamente confuso é o uso de session.Flush
,em conjunto com session.Commit
, e session.Close
.
Às vezes session.Close
funciona, por exemplo, ele compromete-se a todas as mudanças que eu preciso.Eu sei que eu preciso para usar cometer quando eu tiver uma transação, ou uma unidade de trabalho com vários cria/updates/deletes, para que eu possa escolher a reversão se um erro ocorre.
Mas às vezes eu fico realmente intrigado pela lógica atrás session.Flush
.Tenho visto exemplos de onde você tem uma session.SaveOrUpdate()
seguido por um flush, mas quando eu remover o autoclismo funciona bem assim mesmo.Às vezes eu me deparo com erros no Flush declaração dizendo que a sessão expirou, e removê-lo a certeza de que não corri em que erro.
Alguém tem uma boa orientação de como e onde ou quando usar um Flush?Eu verifiquei o NHibernate documentação para isso, mas eu ainda não consigo encontrar uma resposta direta.
Solução
Brevemente:
- Sempre utilize as transações
- Não use
Close()
, em vez quebrar suas chamadas em umaISession
dentro de umusing
instrução ou gerenciar o ciclo de vida do seu ISession em outro lugar.
A partir de a documentação:
De vez em quando
ISession
irá executar as instruções SQL necessárias para sincronizar o ADO.NET estado de conexão com o estado de objetos mantidos na memória.Este processo, flush, ocorre, por padrão, nos seguintes pontos
- a partir de algumas invocações de
Find()
ouEnumerable()
- a partir de
NHibernate.ITransaction.Commit()
- a partir de
ISession.Flush()
As instruções SQL são emitidos na seguinte ordem
- todas as inserções de entidade, na mesma ordem que os objetos correspondentes foram salvos usando
ISession.Save()
- todas as atualizações de entidades
- todas as deleções de coleções
- todos os elementos de coleção exclusões, atualizações e inserções
- todas as inserções de coleção
- todas as deleções de entidade, na mesma ordem que os objetos correspondentes foram excluídos usando
ISession.Delete()
(Uma exceção é que os objetos usando o nativo de geração de ID são inseridos quando eles são salvos.)
Excepto quando explicitamente
Flush()
, não há absolutamente nenhuma garantia sobre quando a Sessão executa o ADO.NET chamadas, apenas a ordem em que eles são executados.No entanto, o NHibernate não garante que oISession.Find(..)
métodos nunca irá retornar dados obsoletos;nem retornam os dados errados.É possível alterar o comportamento padrão para um flush ocorre com menos freqüência.O
FlushMode
classe define três modos diferentes:só lave no tempo de confirmação (e apenas quando o NHibernateITransaction
A API é usada), lave automaticamente usando o explicado rotina, ou nunca lave a menos queFlush()
é chamado explicitamente.O último modo é útil por muito tempo a executar as unidades de trabalho, onde umISession
é mantido aberto e desligado por um longo tempo.
...
Consulte também esta seção:
Terminar uma sessão envolve quatro fases distintas:
- esvaziar a sessão
- confirmar a transação
- fechar a sessão
- tratar exceções
Liberação da Sessão
Se acontecer de você estar usando o
ITransaction
API, você não precisa se preocupar com esta etapa.Será realizada implicitamente quando a transação é confirmada.Caso contrário, você deve chamarISession.Flush()
para garantir que todas as alterações são sincronizadas com o banco de dados.Cometer a transação de banco de dados
Se você estiver usando o NHibernate Transaction API, esta aparência:
tx.Commit(); // flush the session and commit the transaction
Se você estiver gerenciando ADO.NET transações de si mesmo, você deve manualmente
Commit()
o ADO.NET transação.sess.Flush(); currentTransaction.Commit();
Se você decidir não confirmar as alterações:
tx.Rollback(); // rollback the transaction
ou:
currentTransaction.Rollback();
Se você reverter a transação deve ser fechado imediatamente e descartar a sessão atual para garantir que o NHibernate interna do estado é consistente.
Fechar a ISession
Uma chamada para
ISession.Close()
marca o fim de uma sessão.A principal implicação do Close() é que a ADO.NET conexão será abandonada pela sessão.tx.Commit(); sess.Close(); sess.Flush(); currentTransaction.Commit(); sess.Close();
Se você forneceu sua própria conexão,
Close()
retorna uma referência para ele, então você pode fechá-lo manualmente ou devolvê-lo para a piscina.Caso contrário,Close()
retorna para a piscina.
Outras dicas
Começando no NHibernate 2.0, as transações são necessários para DB operações.Por conseguinte, o ITransaction.Commit()
chamada irá lidar com qualquer necessárias rubor.Se, por alguma razão, você não estiver usando o NHibernate transações, então não haverá auto-nivelamento da sessão.
De vez em quando o ISession irá executar as instruções SQL necessárias para sincronizar o ADO.NET estado de conexão com o estado de objetos mantidos na memória.
E use sempre
using (var transaction = session.BeginTransaction())
{
transaction.Commit();
}
depois que as alterações são confirmadas do que isso muda para guardar em banco de dados vamos utilizar a transação.Commit();
Aqui estão dois exemplos de código onde não sem a sessão.Flush():
http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html
no final deste processo, você pode ver uma seção de código onde eu definir a identidade inserir, salvar a entidade, em seguida, esvaziar, em seguida, definir a identidade inserir fora.Sem esta liberação parecia ser a definição de identidade inserir e, em seguida, guardar a entidade.
O uso de Flush() me deu mais controle sobre o que estava acontecendo.
Aqui está outro exemplo:
Enviar NServiceBus mensagem dentro do escopo de transação
Eu não entendemos o porquê, mas o Flush() impediram o meu erro aconteça.