我们遇到了一个间歇性的NHibernate问题,它偶尔会在SQL上生成一个包含错误列的查询。如果我们重新启动应用程序,问题就不会发生(有时需要多次重启)。当问题发生时,在该进程的生命周期内,它总是为受影响的实体生成错误的SQL。It‘s总是同一个受影响的实体。
这是一个在Application_Start事件期间创建SessionFactory的ASP.NET应用程序。所有的配置和映射都是由代码完成的。
我们对如何测试或调试应用程序没有更多的想法,我开始假设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
有趣的观察:
occasionally;
其他细节:
by Code: by Code:
加载映射
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 Configuration
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;
发布于 2014-07-15 17:54:47
我在NHibernate用户谷歌组论坛上问了同样的问题,有人认为他们已经找到了根本原因(并提出了解决方案):
https://groups.google.com/forum/#!topic/nhusers/BZoBoyWQEvs
问题代码在PropertyPath.Equals(PropertyPath)中,它试图仅使用散列代码来确定相等性。这对于较小的代码库很有效,因为默认的Object.GetHashCode()返回一个连续的对象索引。然而,在垃圾收集之后,这些索引被重用,因为最终的对象被删除,新的对象被created...which导致多个对象获得相同的hashcode...Once垃圾收集开始生效,属性路径有机会共享相同的哈希码,这意味着它们最终将混淆冲突属性的定制器,因此错误的列名...
如果你想修复这个bug,你可以修补NH源代码:
如果您有自己的NH源代码副本,可以通过将NHibernate/Mapping/ByCode/PropertyPath.cs第66行从以下位置更改来修复该错误:
return hashCode == other.GetHashCode();
至:
return hashCode == other.GetHashCode() && ToString() == other.ToString();
有关此问题的详细信息,请查看Google Group。
发布于 2014-01-31 17:51:49
检查您的查询日志,看看它在sql中运行的是哪种类型的查询,您可以从中发现问题。
发布于 2014-02-25 01:22:22
看起来"creditcard payments“FATURADEPARCELAMENTO是"lender”对象PRESTADOR上的一个属性,如果是这种情况,它需要是映射中的一个引用而不是一个属性。希望这对你有所帮助,或者至少让你找到正确的方向。
引用将取代您的线属性(x => x.HandlePrestador,map => map.Column("PRESTADOR"));并且将是与引用(x => x.HandlePrestador)相近的内容
https://stackoverflow.com/questions/16991838
复制相似问题