Generando columnas incorrectas en consultas

Estamos teniendo un problema intermitente con NHibernate donde ocasionalmente generará una consulta con una columna incorrecta en el SQL. Si reiniciamos la aplicación, el problema deja de suceder (a veces requiere más de un reinicio). Cuando se produce el problema, durante la vida de ese process, siempre produce el SQL incorrecto para la entidad afectada. No siempre es la misma entidad afectada.

Es una aplicación ASP.NET donde SessionFactory se crea durante el evento Application_Start. Toda la configuration y el mapeo se hacen por código.

No tenemos más ideas sobre cómo probar o depurar la aplicación, y estoy empezando a suponer que hay algún error en NHibernate, ya que la aplicación se corrige al reiniciarse. ¡Cualquier idea / consejo será muy apreciada!

Aquí hay un ejemplo:

Entidad

namespace Example.Clinicas { public partial class Clinica : Entidade // Abstract base class that has a property Handle { public virtual string Ddd { get; set; } public virtual string Ddd2 { get; set; } public virtual long? Duracao { get; set; } public virtual string Numero { get; set; } public virtual string Numero2 { get; set; } public virtual string Prefixo { get; set; } public virtual string Prefixo2 { get; set; } public virtual long? HandlePrestador { get; set; } public virtual Example.Prestadores.Prestador Prestador { get; set; } } } 

Cartografía

 namespace Example.Clinicas.Mappings { public class ClinicaMapping : ClassMapping<Clinica> { public ClinicaMapping() { Table("CLI_CLINICA"); Id(x => x.Handle, map => { map.Column("HANDLE"); map.Generator(Generators.Sequence, g => g.Params(new { sequence = "SEQ_AUTO1816" })); }); Property(x => x.Ddd, map => map.Column( c=> { c.Name("DDD1"); c.Length(4); })); Property(x => x.Ddd2, map => map.Column( c=> { c.Name("DDD2"); c.Length(4); })); Property(x => x.Duracao, map => map.Column("INTERVALOAGENDA")); Property(x => x.Numero, map => map.Column( c=> { c.Name("NUMERO1"); c.Length(5); })); Property(x => x.Numero2, map => map.Column( c=> { c.Name("NUMERO2"); c.Length(5); })); Property(x => x.Prefixo, map => map.Column( c=> { c.Name("PREFIXO1"); c.Length(5); })); Property(x => x.Prefixo2, map => map.Column( c=> { c.Name("PREFIXO2"); c.Length(5); })); Property(x => x.HandlePrestador, map => map.Column("PRESTADOR")); ManyToOne(x => x.Prestador, map => { map.Column("PRESTADOR"); map.Insert(false); map.Update(false); }); } } } 

Mando

 Session.Query<Clinica>().FirstOrDefault(); 

SQL generado

 select HANDLE489_, DDD2_489_, DDD3_489_, INTERVAL4_489_, NUMERO5_489_, NUMERO6_489_, PREFIXO7_489_, FATURADE8_489_, PRESTADOR489_ from (select clinica0_.HANDLE as HANDLE489_, clinica0_.DDD1 as DDD2_489_, clinica0_.DDD2 as DDD3_489_, clinica0_.INTERVALOAGENDA as INTERVAL4_489_, clinica0_.NUMERO1 as NUMERO5_489_, clinica0_.NUMERO2 as NUMERO6_489_, clinica0_.PREFIXO1 as PREFIXO7_489_, clinica0_.FATURADEPARCELAMENTO as FATURADE8_489_, clinica0_.PRESTADOR as PRESTADOR489_ from CLI_CLINICA clinica0_) where rownum <= 1 

Excepción

 ORA-00904: "CLINICA0_"."FATURADEPARCELAMENTO": invalid identifier 

Observaciones interesantes:

  • Es más probable que afecte a entidades más grandes (que tienen un mayor número de properties), pero también afecta a entidades más pequeñas ocasionalmente;
  • El SQL generado siempre tiene el mismo número de columnas que las properties mapeadas;
  • Las columnas en el SQL están en el mismo order que las properties mapeadas en la class de mapeo;
  • La columna incorrecta replaceá a una existente;
  • La columna incorrecta es una columna válida en una entidad asignada diferente;
  • No hay relación entre la entidad afectada y la que tiene la columna incorrecta;

Otros detalles:

  • Versión de .NET: 4.0
  • Versión de NHibernate: 3.3.3.400
  • Asignación por código: NHibernate.Mapping.ByCode
  • Configuración por código: NHibernate.Cfg

Asignaciones de carga

 var mapper = new ModelMapper(); foreach (var assembly in resolver.GetAssemblies()) // resolver is a class that gets all the assemblies for the current application mapper.AddMappings(assembly.GetExportedTypes()); var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); return mapping; 

Configuración de SessionFactory

 var configure = new Configuration(); configure.DataBaseIntegration(x => { x.Dialect<Oracle10gDialect>(); // Custom class x.ConnectionString = ConnectionString; x.BatchSize = 100; x.Driver<OracleMultiQueryDataClientDriver>(); // Custom class x.MaximumDepthOfOuterJoinFetching = 10; x.Timeout = 250; x.PrepareCommands = true; x.HqlToSqlSubstitutions = "true 'S', false 'N', yes 'S', no 'N'"; x.LogFormattedSql = true; x.LogSqlInConsole = true; x.AutoCommentSql = true; x.IsolationLevel = IsolationLevel.ReadCommitted; x.ConnectionProvider<ConnectionProvider>(); // Custom class }); configure.Properties.Add(new KeyValuePair<string, string>("hibernate.command_timeout", "250")); configure.Proxy(x => x.ProxyFactoryFactory<NHibernate.Bytecode.DefaultProxyFactoryFactory>()); configure.LinqToHqlGeneratorsRegistry<LinqToHqlGeneratorsRegistry>(); configure.CurrentSessionContext<NHibernate.Context.WebSessionContext>(); var mapping = GetMappings(); // Method showed above mapping.autoimport = false; configure.AddMapping(mapping); var listener = new AuditEventListener(); configure.EventListeners.PostInsertEventListeners = new IPostInsertEventListener[] { listener }; configure.EventListeners.PostUpdateEventListeners = new IPostUpdateEventListener[] { listener }; configure.SessionFactory().GenerateStatistics(); return configure; 

Hice la misma pregunta en el foro de Grupos de Google de usuarios de NHibernate, y alguien cree que han resuelto la causa raíz (y también han propuesto una solución):

https://groups.google.com/forum/#!topic/nhusers/BZoBoyWQEvs

El código del problema está en PropertyPath.Equals (PropertyPath) que intenta determinar la igualdad utilizando solo el código hash. Esto funciona bien para bases de código más pequeñas como Object.GetHashCode () pnetworkingeterminado devuelve un índice de object secuencial. Sin embargo, después de la recolección de basura, estos índices se reutilizan cuando se eliminan los objects finalizados y se crean nuevos objects … lo que hace que más de un object obtenga el mismo código hash … Una vez que se inicia la recolección de basura, los paths de propiedad tienen la oportunidad de compartir el mismo código hash, lo que significa que finalmente mezclarán sus personalizadores para las properties que colisionan, por lo tanto, los nombres de columnas incorrectos …

Si desea corregir este error, puede aplicar un parche al código fuente de NH:

Si tiene su propia copy de la fuente NH, puede corregir el error cambiando NHibernate / Mapping / ByCode / PropertyPath.cs línea # 66 desde:

return hashCode == other.GetHashCode();

A:

return hashCode == other.GetHashCode() && ToString() == other.ToString();

Consulte el Grupo de Google para get más detalles sobre el problema.

parece que los "pagos con tarjeta de crédito" FATURADEPARCELAMENTO es una propiedad de su object "prestamista" PRESTADOR, si este es el caso, debe ser una reference y NO una propiedad en el mapeo. Espero que ayude o al less te apunte en la dirección correcta

la reference tomaría el lugar de su línea Propiedad (x => x.HandlePrestador, map => map.Column ("PRESTADOR")); y sería algo cercano a References (x => x.HandlePrestador)

Revise su logging de consulta para ver qué tipo de consulta está ejecutando, en su SQL desde allí usted, puede detectar el problema.