Pergunta

Ao usar o Rhino Commons UnitOfwork (em uma unidade de aplicativo para asp-mvc), gosto de usar a classe estática do Rhino Repository para salvar entidades como esta:

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

Acho que posso tirar a entidade imediatamente após essa chamada usando:

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

Isso funciona bem. No entanto, quando uso o provedor LINQ Nibernate em Rhino UnitOfwork como este:

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

Eu recebo uma lista vazia. Parece que tenho que ligar para o UnitOfwork.current.flush () antes que eu possa tirar o carro assim. Não entendo por que, dado que nos bastidores, presumo que ambos os métodos de recuperação estão consultando a mesma sessão / unidade de trabalho. Isso significa que você deve ligar para o UnitOfwork.current.flush () após cada salvar no banco de dados? Nibernate não deveria conseguir descobrir quando se libertar? Ou estou entendendo mal algo?

Foi útil?

Solução

Ok, parece que, embora uma ligação para o repositório possa usar o cache da sessão, pode 'ver' o carro salvo no cache:

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

Uma consulta LINQ não usa o cache da sessão:

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

Portanto, as melhores práticas são as alterações do banco de dados (salvar, atualizar, excluir, inserir) devem ser seguidas por:

UnitOfWork.Session.Flush(), 

ou embrulhado em A:

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

ou decore seu método com [transação] e use o ATM. Isso garantirá que as consultas LINQ subsequentes analisarão dados atualizados.

Outras dicas

Quando você liga para o repositório.Save, você está notificando a sessão mantida pelo repositório para rastrear esse objeto e sincronizar as alterações no banco de dados no próximo Flush. Até você liberar a sessão, nenhuma alteração é feita no banco de dados. O objeto se torna parte do cache da sessão e, portanto, será devolvido pelo GET (1).

Quando você executa uma consulta para preencher uma coleção, a sessão consulta o banco de dados para obter os resultados, a menos que já tenha armazenado esses resultados. Como você ainda não atualizou o banco de dados, o carro que você adicionou à sessão não fará parte do conjunto de resultados. (<-Possivelmente incorreto) Se estiver lendo a documentação corretamente, os resultados da consulta e as entidades SAVE () devem ser adicionadas ao cache da sessão (de primeiro nível). Isso não significa necessariamente que o querystatement.List() Consulta o cache depois de adicionar os resultados do banco de dados ... Estou tendo dificuldade em envolver a cabeça exatamente o que está acontecendo.

Como um aparte, acredito que você pode definir a sessão para Autoflush, mas eu teria que verificar a documentação.

ATUALIZAR:

Eu acho que posso ver o que está acontecendo aqui. A sessão padrão FlushMode é Auto Mas rinocerontes UnitOfWork.Start() cria uma sessão com um FlushMode definido como Commit, o que significa que a sessão não será descartada automaticamente, a menos que você ligue explicitamente Flush() ou cometer a transação. Com um FlushMode do Auto, Nibernate Will (às vezes?) Libere a sessão antes de consultar para impedir que dados obsoletos sejam devolvidos. Se eu estiver certo, sua transação de banco de dados é algo como:

SELECT * FROM Car

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

Quando o Auto Flushes parece um pouco ambíguo a partir da documentação/blogs que li ... a resposta mais comum é que ela FlushMode = Auto ele libera "às vezes", embora garante que Session.Find nunca retornará dados obsoletos. Como o Nhibernate Linq realmente apenas cria uma consulta de critérios, pode não acionar o rubor automático (talvez isso tenha sido corrigido agora ... é difícil saber).

Então, parece -me que, no seu caso, você deseja descarregar após o seu salvamento, porque deseja recuperar imediatamente os resultados do seu salvamento. Em uma unidade de trabalho menor em que você estava atualizando apenas entidades, um único commit () seria bom. Pode ser UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto; Faria o truque, mas o fato de a fábrica da UOW definir explicitamente o modo a se comprometer parece estar incentivando você a realmente pensar nos limites dos seus uow.

Graças a Stuart Childs, suspeito que ele esteja certo que a questão possa estar com o fornecedor da Nibernate Linq. Não tenho certeza do que faz nos bastidores, mas pode usar uma sessão diferente, se o fizer, faz sentido que eu precise liberar o repositório salvar antes que a consulta do Linq 'veja'. Hora de examinar o código -fonte, mas me disseram que ele derreterá minha cabeça tentando entender!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top