gpt4 book ai didi

c# - 在查询中生成错误的列

转载 作者:IT王子 更新时间:2023-10-29 04:50:37 25 4
gpt4 key购买 nike

我们在使用 NHibernate 时遇到间歇性问题,它偶尔会在 SQL 中生成包含错误列的查询。如果我们重新启动应用程序,问题将不再发生(有时需要不止一次重新启动)。当问题发生时,在该进程的生命周期内,它总是为受影响的实体生成错误的 SQL。它总是同一个受影响的实体。

它是一个 ASP.NET 应用程序,其中 SessionFactory 在 Application_Start 事件期间创建。所有的配置和映射都是通过代码完成的。

我们不知道如何测试或调试应用程序,我开始假设 NHibernate 中存在一些错误,因为应用程序会在重新启动时自行修复。任何想法/提示将不胜感激!

这是一个例子:

实体

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

映射

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

有趣的观察:

  • 它更有可能影响较大的实体(具有更多属性),但偶尔也会影响较小的实体;
  • 生成的 SQL 始终具有与映射属性相同的列数;
  • SQL 中的列与映射类中的映射属性的顺序相同;
  • 错误的列将替换现有的列;
  • 错误的列是不同映射实体中的有效列;
  • 受影响的实体与列有错误的实体之间没有任何关系;

其他细节:

  • .NET 版本:4.0
  • NHibernate 版本:3.3.3.400
  • 按代码映射: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;

session 工厂配置

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;

最佳答案

我在 NHibernate Users Google Groups 论坛上问了同样的问题,有人认为他们已经找到了根本原因(并且还提出了解决方案):

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

The problem code is in PropertyPath.Equals(PropertyPath) which attempts to determine equality by only using the hash code. This works fine for smaller code bases as the default Object.GetHashCode() returns a sequential object index. However, after garbage collection, these indices get reused as finalized objects are removed and new objects are created...which results in more than one object getting the same hashcode...Once garbage collection kicks in, property paths have a chance to share the same hashcode which means they will ultimately mix up their customizers for the colliding properties, thus the wrong column names...

如果你想修复这个bug,你可以修补NH源代码:

If you have your own copy of the NH source, you can fix the bug by changing NHibernate/Mapping/ByCode/PropertyPath.cs line #66 from:

return hashCode == other.GetHashCode();

To:

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

有关问题的完整详细信息,请查看 Google 网上论坛。

关于c# - 在查询中生成错误的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16991838/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com