sql - NHibernate - 查询中的列错误

标签 sql nhibernate nhibernate-mapping nhibernate-criteria

我遇到了 NHibernate 的间歇性问题,它为实体生成查询,但将其中一列替换为来自完全不同(且不相关)的实体的列。

它只替换单个列,并且通常通过重新启动应用程序来解决(尽管有时需要几次尝试)。

  • ASP.NET 应用程序 (.NET 4.0)
  • 在 Application_Start 期间创建的 SessionFactory
  • NHibernate 3.3.1- 通过 Mapping By Code 完成的所有映射/配置
  • 使用 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");
            }
        }
    

    SQL 查询,由 NHibernate 生成
    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_
    

    异常(exception)
    System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'InitialAmountUSD'.
    

    如您所见,nhibernate 已将 LiquiditySourceItem 列“Traderevalcurr”替换为“InitialAmountUSD”,后者属于 BusinessBreakdownStandardPosition 实体。这些实体没有任何关系。否则,SQL 完全符合您的预期(包括列顺序)。

    观察
  • 错误的列始终是不同映射实体中的有效列
  • 错误的列将替换现有的列
  • 该问题有时会发生在其他实体之间。同样,这些
  • 之间没有任何关系。

    有什么想法吗?

    最佳答案

    我在 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 Group 以了解问题的完整详细信息。

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

    相关文章:

    mysql - 返回至少有 2 个不同订单的员工,其中订单中某些产品的数量 >= 5

    fluent-nhibernate - 手动设置 ID

    nhibernate - 映射可能没有行的扩展表

    sql-server - 处理 UTC、时区并使用 LocalTime 对其进行 GROUP BY

    NHibernate 使用 Cascade.All 执行删除会导致 N+1 删除

    c# - ServiceStack/FluentNHibernate/MySQL - 两个并发请求使用同一连接

    nhibernate - 如何在NHibernate hbm.xml映射文件中映射VARCHAR(MAX)列

    php - MySql语法错误;可以在一个查询中删除两个表吗?

    SQL 查询 If not null, then update or else keep the same data

    行之间的 SQL 比率