NHibernate Session.Flush() Enviando consultas de atualização quando nenhuma atualização ocorreu

StackOverflow https://stackoverflow.com/questions/34852

  •  09-06-2019
  •  | 
  •  

Pergunta

Eu tenho uma sessão do NHibernate.Nesta sessão, estou realizando exatamente 1 operação, que é executar este código para obter uma lista:

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

eu estou chamando Session.Flush() no final de HttpRequest, e eu recebo um HibernateAdoException.O NHibernate está passando uma instrução de atualização para o banco de dados e causando uma violação de chave estrangeira.Se eu não executar o flush, a solicitação será concluída sem problemas.O problema aqui é que preciso do flush caso haja alguma alteração que ocorra em outras sessões, já que esse código é reaproveitado em outras áreas.Há outra configuração que possa estar faltando?


Aqui está o código da exceção:

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

Nenhum parâmetro está sendo mostrado como sendo passado.

Foi útil?

Solução

Já vi isso uma vez, quando um dos meus modelos não foi mapeado corretamente (não estava usando tipos anuláveis ​​corretamente).Você pode colar seu modelo e mapeamento?

Outras dicas

Sempre tenha cuidado com os campos NULLable sempre que lidar com o NHibernate.Se o seu campo for NULLable no banco de dados, certifique-se de que a classe .NET correspondente também use o tipo Nullable.Caso contrário, todo tipo de coisas estranhas acontecerão.O sintoma geralmente é que o NHibernate tentará atualizar o registro no banco de dados, mesmo que você não tenha alterado nenhum campo desde que leu a entidade do banco de dados.

A sequência a seguir explica por que isso acontece:

  1. NHibernate recupera dados brutos da entidade do banco de dados usando ADO.NET
  2. NHibernate constrói a entidade e define suas propriedades
  3. Se o campo DB contiver NULL, a propriedade será definida com o valor padrão para seu tipo:
    • propriedades dos tipos de referência serão definidas como nulas
    • propriedades dos tipos inteiro e ponto flutuante serão definidas como 0
    • propriedades do tipo booleano serão definidas como falsas
    • propriedades do tipo DateTime serão definidas como DateTime.MinValue
    • etc.
  4. Agora, quando a transação é confirmada, o NHibernate compara o valor da propriedade com o valor do campo original, ele lê o formulário DB e, como o campo contém NULL, mas a propriedade contém um valor não nulo, O NHibernate considera a propriedade suja e força uma atualização da entidade.

Isso não apenas prejudica o desempenho (você obtém uma viagem de ida e volta extra ao banco de dados e atualizações extras sempre que recupera a entidade), mas também pode dificultar a solução de erros com colunas DateTime.Na verdade, quando a propriedade DateTime é inicializada com seu valor padrão, ela é definida como 1/1/0001.Quando esse valor é salvo no banco de dados, o SqlClient do ADO.NET não pode convertê-lo em um valor SqlDateTime válido, pois o menor SqlDateTime possível é 1/1/1753!!!

A solução mais fácil é fazer com que a propriedade da classe use o tipo Nullable, neste caso "DateTime?".Alternativamente, você pode implementar um mapeador de tipo personalizado implementando IUserType com seu método Equals comparando adequadamente DbNull.Value com qualquer valor padrão do seu tipo de valor.Em nosso caso, Equals precisaria retornar verdadeiro ao comparar 1/1/0001 com DbNull.Value.Implementar um IUserType totalmente funcional não é tão difícil, mas requer conhecimento de curiosidades do NHibernate, então prepare-se para fazer algumas pesquisas substanciais no Google se você decidir seguir esse caminho.

Também tive esse problema no NH 2.0.1 ao tentar ocultar as extremidades inversas de sacos muitos para muitos usando access="noop" (dica:isso não funciona).

Convertê-los para access="field" + adicionar um campo na classe resolveu o problema.É muito difícil rastreá-los.

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