我遇到了NHibernate的间歇性问题,该问题会为实体生成查询,但是用来自完全不同(且不相关)的实体的列替换了其中的一列。
它只能替换单个列,通常可以通过重新启动应用程序来解决(尽管有时需要进行几次尝试)。
任何输入对此将不胜感激!
实体
public class LiquiditySourceItem : RunDataEntity, IEntity<int> { public virtual int Id { get; protected internal set; } public virtual int IdentID { get; protected internal set; } public virtual string Portfolio { get; protected internal set; } public virtual string ProfitCentre { get; protected internal set; } public virtual DateTime? MaturityDate { get; protected internal set; } public virtual string Curr1 { get; protected internal set; } public virtual string Curr2 { get; protected internal set; } public virtual decimal Reval { get; protected internal set; } public virtual string ContractType { get; protected internal set; } public virtual string ContractType2 { get; protected internal set; } public virtual string ContractCode { get; protected internal set; } public virtual decimal AmountSignedTradeUnit { get; protected internal set; } public virtual decimal Amount2Signed { get; protected internal set; } public virtual decimal SpotDelta { get; protected internal set; } public virtual string TradeRevalCurr { get; protected internal set; } }
实体映射
public LiquiditySourceItemMap() { Id(x => x.Id, map => map.Column("RowId")); Property(x => x.IdentID, map => map.Column("IdentID")); Property(x => x.Portfolio, map => map.Column("Portfolio")); Property(x => x.ProfitCentre, map => map.Column("ProfitCentre")); Property(x => x.MaturityDate, map => map.Column("Con_Expiry")); Property(x => x.BuySell, map => map.Column("BS")); Property(x => x.Curr1, map => map.Column("Curr1")); Property(x => x.Curr2, map => map.Column("Curr2")); Property(x => x.Reval, map => map.Column("Reval")); Property(x => x.ContractType, map => map.Column("ContractType")); Property(x => x.ContractType2, map => map.Column("ContractType2")); Property(x => x.ContractCode, map => map.Column("ContractCode")); Property(x => x.AmountSignedTradeUnit, map => map.Column("AmountSignedTradeUnit")); Property(x => x.Amount2Signed, map => map.Column("Amount2Signed")); Property(x => x.ValSpot, map => map.Column("Val_Spot")); Property(x => x.SpotDelta, map => map.Column("SpotDelta")); Property(x => x.TradeRevalCurr, map => map.Column("Traderevalcurr")); Property(x => x.SourceReport, map => map.Column("SourceReport")); ManyToOne(x => x.RunContext, map => map.Column("RunContextID")); Table("Staging.vw_Liquidity"); }
报告实体
public class BusinessBreakdownStandardPosition : ReportRunDataEntity, IEntity<long> { public virtual long Id { get; set; } public virtual decimal FinalNettingAmountUSD { get; set; } public virtual decimal InitialChargeAmountUSD { get; set; } public virtual BusinessBreakdownInitialPrr InitialPrr { get; set; } public virtual IEnumerable<FinalInstrumentPosition> FinalInstrumentPositions { get; set; } public virtual decimal CreditEventPaymentUSD { get; set; } public virtual decimal ValuationChangeIncreaseUSD { get; set; } public virtual decimal ValuationChangeDecreaseUSD { get; set; } public virtual string ReportKey { get; set; } public virtual decimal USDCharge { get; set; } public virtual decimal USDChargeICG { get; set; } public virtual string InstrumentType { get; set; } }
报告实体映射
public class BusinessBreakdownStandardPositionMap : ClassMapping<BusinessBreakdownStandardPosition> { public BusinessBreakdownStandardPositionMap() { Id(x => x.Id, m => { m.Column("BusinessBreakdownStandardPositionID"); m.Generator(Generators.HighLow, g => g.Params( new { table = "dbo.HiValue", max_lo = 10000, Where = string.Format("EntityName = 'BusinessBreakdownStandardPosition'") })); }); Property(x => x.FinalNettingAmountUSD, map => map.Column("FinalNettingAmountUSD")); Property(x => x.InitialChargeAmountUSD, map => map.Column("InitialAmountUSD")); Property(x => x.CreditEventPaymentUSD); Property(x => x.ValuationChangeDecreaseUSD); Property(x => x.ValuationChangeIncreaseUSD); Property(x => x.USDCharge); Property(x => x.USDChargeICG); Property(x=>x.InstrumentType); ManyToOne(p => p.RunContext, map => map.Column("ReportRunContextID")); ManyToOne(p => p.InitialPrr, m => { m.Column("InitialPrrID"); m.Cascade(Cascade.All); }); Property(x => x.ReportKey); Bag(x => x.FinalInstrumentPositions, collectionMapping => { collectionMapping.Table("Reporting.BusinessBreakdownFinalInstrumentPositionStandardPositionMap"); collectionMapping.Cascade(Cascade.All); collectionMapping.Key(k => k.Column("StandardPositionID")); }, mapping => mapping.ManyToMany(y => y.Column("FinalInstrumentPositionID"))); Table("Reporting.BusinessBreakdownStandardPosition"); } }
NHibernate生成的SQL查询
SELECT this_.RowId AS RowId47_0_, this_.IdentID AS IdentID47_0_, this_.Portfolio AS Portfolio47_0_, this_.ProfitCentre AS ProfitCe4_47_0_, this_.Con_Expiry AS Con5_47_0_, this_.BS AS BS47_0_, this_.Curr1 AS Curr7_47_0_, this_.Curr2 AS Curr8_47_0_, this_.Reval AS Reval47_0_, this_.ContractType AS Contrac10_47_0_, this_.ContractType2 AS Contrac11_47_0_, this_.ContractCode AS Contrac12_47_0_, this_.AmountSignedTradeUnit AS AmountS13_47_0_, this_.Amount2Signed AS Amount14_47_0_, this_.Val_Spot AS Val15_47_0_, this_.SpotDelta AS SpotDelta47_0_, this_.InitialAmountUSD AS Initial17_47_0_, this_.RunContextID AS RunCont18_47_0_, this_.SourceReport AS Sou19_47_0_ FROM Staging.vw_Liquidity this_
例外
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'InitialAmountUSD'.
如您所见,nhibernate已将LiquiditySourceItem列’Traderevalcurr’替换为’InitialAmountUSD’,该列属于BusinessBreakdownStandardPosition实体。这些实体没有任何关系。否则,SQL完全符合您的期望(包括列顺序)。
观察结果
有什么想法吗?
我在NHibernate用户Google网上论坛上问了同样的问题,有人认为他们已经找到了根本原因(并且还提出了解决方案):
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(); 到: return hashCode == other.GetHashCode() && ToString() == other.ToString();
如果您拥有自己的NH源副本,则可以通过将NHibernate / Mapping / ByCode / PropertyPath.cs第66行从以下位置更改来修复该错误:
return hashCode == other.GetHashCode();
到:
return hashCode == other.GetHashCode() && ToString() == other.ToString();
请查看Google网上论坛以获取问题的完整详细信息。