2013-06-07 3 views
18

У нас возникает проблема с NHibernate, которая периодически вызывает запрос с неправильным столбцом SQL. Если перезапустить приложение, проблема перестает появляться (иногда требуется более одного перезапуска). Когда возникает проблема, в течение всего жизненного цикла этого процесса он всегда создает неправильный SQL для затронутого объекта. Это не всегда один и тот же объект.Создание неправильных столбцов по запросам

Это приложение ASP.NET, в котором SessionFactory создается во время события Application_Start. Вся конфигурация и сопоставление выполняются с помощью кода.

У нас больше нет идей, как тестировать или отлаживать приложение, и я предполагаю, что в NHibernate есть некоторая ошибка, так как приложение исправляет себя при перезагрузке. Любые идеи/советы будут высоко оценены!

Here's пример:

Entity

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; } 
    } 
} 

Mapping

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); 
      }); 
     } 
    } 
} 

Команда

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

Сгенерированный SQL

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 

Исключение

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

Интересные наблюдения:

  • Это, скорее всего, влияет на большую entit (который имеет большее количество свойств), но также иногда затрагивает небольшие субъекты;
  • Сгенерированный SQL всегда имеет такое же количество столбцов, что и отображаемые свойства;
  • Столбцы на SQL находятся в том же порядке, что и сопоставленные свойства в классе сопоставления;
  • Неправильный столбец заменит существующий;
  • Неправильный столбец является допустимым столбцом в другой сопоставленной сущности;
  • Между затронутым объектом и тем, у которого есть неправильный столбец, нет никакой связи;

Другие детали:

  • версии .NET: 4,0
  • NHibernate Версия: 3.3.3.400
  • Mapping по коду: NHibernate.Mapping.ByCode
  • Конфигурация с помощью кода: NHibernate.Cfg

нагрузки Отображения

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; 

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; 
+0

У вас есть несколько объектов, сопоставленных с одной и той же базой данных? – rivarolle

+0

Есть некоторые, но не в этом случае. Клиника является единственным сопоставленным объектом в таблице CLI_CLINICA. –

+0

Всегда ли ссылается на тот же недопустимый столбец? – mxmissile

ответ

1

Проверьте querylog, чтобы увидеть, какой тип запроса его runnig, в вашем sql оттуда вы можете обнаружить проблему.

1

похоже, что «платежи по кредитным картам» FATURADEPARCELAMENTO является собственностью объекта «кредитор» PRESTADOR, если это так, он должен быть ссылкой и НЕ являться свойством в сопоставлении. Надеюсь, что это поможет или, по крайней мере, поможет вам указать направление в правильном направлении.

Ссылка будет заменена вашей линией Недвижимость (x => x.HandlePrestador, map => map.Column ("PRESTADOR")); и будет что-то близко к Ссылки (х => x.HandlePrestador)

4

я задал тот же вопрос о NHibernate пользователей Google Groups форум, а кто-то думает, что они разработали основную причину (а также предложил раствор):

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

код проблема заключается в PropertyPath.Equals (PropertyPath), который пытается определить равенство только с помощью хэш-код. Это отлично подходит для небольших базовых кодов, поскольку по умолчанию Object.GetHashCode() возвращает индекс последовательного объекта. Тем не менее, после сбора мусора эти индексы повторно используются, поскольку финализированные объекты удаляются, и создаются новые объекты ... что приводит к тому, что несколько объектов получают один и тот же хэш-код ... После того, как сбор мусора начинается, пути собственности имеют шанс поделиться тот же хэш-код, который означает, что они будут в конечном счете, перепутать их настройщик для сталкивающихся свойств, таким образом неправильных имен столбцов ...

Если вы хотите, чтобы исправить эту ошибку, вы можете исправить исходный код NH:

Если у вас есть собственная копия источника NH, вы можете исправить ошибку, изменив NHibernate/Mapping/ByCode/PropertyPath.cs строку # 66 от:

return hashCode == other.GetHashCode();

To:

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

Пожалуйста, проверьте группу Google для получения полной информации о проблеме.

Смежные вопросы