NHibernate-查询错误的列 [英] NHibernate - Wrong Columns on Queries

查看:76
本文介绍了NHibernate-查询错误的列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在NHibernate中遇到一个间歇性问题,它会生成一个实体查询,但是用完全不同(且不相关)实体的列替换了其中的一列.

I'm getting an intermittant problem with NHibernate where it generates a query for an entity, but replaces one of the columns with a column from completely different (and unrelated) entity.

它只能替换单个列,通常可以通过重新启动应用程序来解决(尽管有时需要进行几次尝试).

It only ever replaces a single column, and is generally solved by restarting the application (though sometimes it takes a couple of attempts).

  • ASP.NET应用程序(.NET 4.0)
  • 在Application_Start期间创建的SessionFactory
  • NHibernate 3.3.1-通过代码映射完成所有映射/配置
  • 使用休眠标准

对此表示感谢!

实体

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会完全符合您的期望(包括列顺序).

As you can see, nhibernate has replaced the LiquiditySourceItem column 'Traderevalcurr' with 'InitialAmountUSD', which belongs to the BusinessBreakdownStandardPosition entity. These entities have no relationship whatsoever. Otherwise, the SQL is exactly as you'd expect( including column order).

观察

  • 错误的列始终是另一个映射实体中的有效列
  • 错误的列将替换现有的列
  • 其他实体之间有时会出现此问题.同样,这些之间没有任何关系

有什么想法吗?

推荐答案

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

I asked the same question on the NHibernate Users Google Groups forum, and someone thinks they have worked out the root cause (and have also proposed a solution):

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

问题代码在PropertyPath.Equals(PropertyPath)中,该属性试图仅通过使用哈希码来确定相等性.这对于较小的代码库来说效果很好,因为默认的Object.GetHashCode()返回一个顺序的对象索引.但是,在垃圾回收之后,这些索引会在删除最终对象并创建新对象时重新使用...导致多个对象获得相同的哈希码...一旦垃圾回收开始,属性路径就有机会共享相同的哈希码,这意味着他们最终将为冲突的属性混合使用其定制程序,因此列名称错误...

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...

如果要解决此错误,可以修补NH源代码:

If you want to fix this the bug, you can patch the NH source code:

如果您拥有自己的NH源副本,则可以通过将NHibernate/Mapping/ByCode/PropertyPath.cs第66行从以下位置更改来修复该错误:

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

收件人:

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

请查看Google网上论坛以获取有关该问题的完整详细信息.

Please check out the Google Group for full details of the issue.

这篇关于NHibernate-查询错误的列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆