将 ODP.Net 与 NHibernate 与 .net System.decimal 一起使用
Posted
技术标签:
【中文标题】将 ODP.Net 与 NHibernate 与 .net System.decimal 一起使用【英文标题】:Using ODP.Net with NHibernate with .net System.decimal 【发布时间】:2011-05-17 23:41:16 【问题描述】:我正在使用 ODP.net 针对 Oracle 10g 数据库运行聚合 AVG。我直接在数据库上运行这个查询,它工作正常:
从 IHObjekt 中选择 avg(ANSCHAFFUNGSKST)
返回:13.4493973163521
HQL 和 CreateCriteria 接口均成功执行查询。我收到 NHibernate '无法执行查询' 消息。但是,我相对确定这是基于 posting 的 ODP.Net 错误。
Oracle 有一个解决方案,只需 TRUNC AVG。但是,TRUNC 命令在 Oracle 和 SQL Server 中是不同的,我需要/不想让我的代码成为特定于数据库的代码。
关于如何减少小数点数以使其适合小数,最重要的是,它适用于所有数据库的任何想法?
来源 = NHibernate
堆栈跟踪
NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters) NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) NHibernate.Impl.SessionImpl.List(字符串查询,QueryParameters 参数) NHibernate.Impl.QueryImpl.List() DBTest_NHibernate.MainWindow.ButtonHQLQuery_Click(Object sender, RoutedEventArgs e) in C:\...内部异常
[System.OverflowException] = "Die arithmetische Operation hat einen Überlauf verursacht." ... 算术运算导致溢出。
来源 = Oracle.DataAccess
堆栈跟踪
Oracle.DataAccess.Types.DecimalConv.GetDecimal(IntPtr numCtx) Oracle.DataAccess.Client.OracleDataReader.GetDecimal(Int32 i) Oracle.DataAccess.Client.OracleDataReader.GetValue(Int32 i) Oracle.DataAccess.Client.OracleDataReader.get_Item(Int32 i) NHibernate.Type.DoubleType.Get(IDataReader rs, Int32 索引) NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, 字符串名称) NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner) NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.GetResultColumnOrRow(Object[] row, IResultTransformer resultTransformer, IDataReader rs, ISessionImplementor session) NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydradObjects, EntityKey[] 键, Boolean returnProxies) NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)部分 HQL 测试结果
从 IHObjekt 中选择 TRUNC(AVG(ANSCHAFFUNGSKST),27) - WORKS(仅在 ORACLE 中) 从 IHObjekt 中选择 TRUNC(AVG(ANSCHAFFUNGSKST),28) - 不起作用 从 IHObjekt 中选择 AVG(ANSCHAFFUNGSKST) - 不起作用NHibernate 生成的 SQL
SELECT
AVG(IHOBJEKT0_.ANSCHAFFUNGSKST) AS COL_0_0_,
COUNT(IHOBJEKT0_.ANSCHAFFUNGSKST) AS COL_1_0_,
MAX(IHOBJEKT0_.ANSCHAFFUNGSKST) AS COL_2_0_,
MIN(IHOBJEKT0_.ANSCHAFFUNGSKST) AS COL_3_0_,
SUM(IHOBJEKT0_.ANSCHAFFUNGSKST) AS COL_4_0_
FROM
IHOBJEKT IHOBJEKT0_
只有 AVG 在使用 ODP.Net 的 Oracle 上的上述 SQL 语句中不起作用。使用 SQL Server 或 Oracle 客户端即可。
【问题讨论】:
发布完整的异常,包括堆栈跟踪。 能贴出nhiberate生成的查询吗? 【参考方案1】:通过剖析我得到的代码并将其切割成更小的部分,我可以确认,在使用逗号右侧数字过多的双精度时会遇到问题。
与 OP 相比,TRUNC(AVG(XXXX)) 在我的情况下不起作用。然而:
TRUNC(doubledigit, intvalue) 和 ROUND(doubledigit, intvalue)
带来了解决方案。我使用 odp.net 使用 nhibernate 和一个简单的 OracleDataReader 对此进行了测试
【讨论】:
【参考方案2】:问题是由于小数点后的值的数量,返回的值不会转换为 .Net Decimal。看起来即使值被.Net四舍五入,Oracle内部也会抛出溢出异常。
从我所阅读的内容来看,Oracle 已确认这是设计使然,不会更改。
有些人使用 Trunc 或 cating 到一个字符串然后一个 double 来解决这个问题。
【讨论】:
感谢您的输入,但我的目标是防止系统包含特定于数据库的代码。该查询直接在 SQL Server 和 Oracle 上运行,但不能通过 ODP.Net。以上是关于将 ODP.Net 与 NHibernate 与 .net System.decimal 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
EF for Oracle,dotConnect for Oracle,ODP.NET
将 System.Data.OracleClient 替换为 Oracle.DataAccess (ODP.NET)