【问题标题】:NHibernate System.IndexOutOfRangeExceptionNHibernate System.IndexOutOfRangeException
【发布时间】:2016-11-25 21:23:54
【问题描述】:

我有一个非常简单的类,它给出了一个奇怪的错误。该类只有 1 个属性,查询非常简单。最令人窒息的部分是这似乎是随机发生的。收到此错误后,通常刷新页面会使其正常运行,并且应用程序不会再次收到错误。

这可能是数据库连接的问题吗?

我明白了:

[IndexOutOfRangeException: Department5_]
   System.Data.ProviderBase.FieldNameLookup.GetOrdinal(String fieldName) +4839010
   System.Data.SqlClient.SqlDataReader.GetOrdinal(String name) +67
   NHibernate.Driver.NHybridDataReader.GetOrdinal(String name) +46
   NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name) +87
   NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner) +62
   NHibernate.Loader.Loader.GetKeyFromResultSet(Int32 i, IEntityPersister persister, Object id, IDataReader rs, ISessionImplementor session) +213
   NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies) +301
   NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +1422
   NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +114
   NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +205

[ADOException: could not execute query
[ select department0_.Department as Department5_ from tblDepartments department0_ where department0_.Department like 'CBS - %' ]
[SQL: select department0_.Department as Department5_ from tblDepartments department0_ where department0_.Department like 'CBS - %']]
   NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +383
   NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) +52
   NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) +183
   NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters) +102
   NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) +684
   NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) +816
   NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) +277
   NHibernate.Impl.SessionImpl.List(String query, QueryParameters parameters) +235
   NHibernate.Impl.QueryImpl.List() +224
   DispatchBoard.Models.Repository.Find(String hql) +76
   DispatchBoard.Controllers.HomeController.Filter() +48
   lambda_method(ExecutionScope , ControllerBase , Object[] ) +39
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +178
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +24
   System.Web.Mvc.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7() +52
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +254
   System.Web.Mvc.<>c__DisplayClassc.<InvokeActionMethodWithFilters>b__9() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399
   System.Web.Mvc.Controller.ExecuteCore() +126
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
   System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151
   System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57
   System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

这是我的课

public class Department : IObject {
    public virtual string Name { get; set; }
}

hbm 文件

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="DispatchBoard.Models.Department, DispatchBoard" table="tblDepartments">
        <id name="Name" column="Department" type="String" length="50">
            <generator class="assigned" />
        </id>

    </class>
</hibernate-mapping>

这里是 HQL 查询

var hql = "from Department d where d.Name like 'CBS - %'";
_session.CreateQuery(hql).List<T>();

【问题讨论】:

  • 所以你说这个类/映射/查询是完整的,这里有什么遗漏吗?
  • 在这之前发生了一些查询,使用不同的类,但这是完整的查询和映射。这对我来说没有意义。
  • 在查询之前,NHibernate 刷新会话以确保查询到更新的数据。因此,这可能是由于您在此查询之前所做的内存更改而发生的。尽管堆栈跟踪看起来不像这样,但仍然尝试在查询之前调用 session.Flush() 以查看它是在刷新期间还是在查询期间发生。无论如何检查这个其他类的映射。

标签: nhibernate


【解决方案1】:

通常,当您在 NHibernate 中获得 IndexOutOfRangeException 时,这是因为您将一个属性映射了两次,或者将两个属性映射到同一列。检查列名。

它可能是随机发生的,因为冲突只出现在某个数据星座中。

【讨论】:

  • 感谢您的建议。查询是针对只有 1 个属性(名称)且没有关系的类。如果刷新页面(再次运行查询)它将正常工作。它每次都获得相同的数据。此查询没有变化。在上面的 hbm 文件中,我只定义了 id 映射。它没有被映射两次。
  • 我以不同的方式弄乱了我的映射属性。您的评论为我指明了正确的方向。谢谢!
  • 就我而言,我是同一列的 idParent 财产和多对一父母。谢谢!工作正常。
【解决方案2】:

我们 - 和其他人 - 最近和过去也遇到过这个问题。它似乎与对非线程安全SqlConnection 的多线程访问有关。以下非常长 (!) 帖子包含更多示例和有关该问题的更多详细信息:SQLDataReader.GetOrdinal() fails rarely with IndexOutOfRange。还有bbzippo声明:

"显然 SqlDataReader 读取 遗留下来的结果集 上一个查询在同一个上执行 几秒钟前的连接。”

不幸的是,我还没有找到任何真正的解释来解释为什么这个异常会在一段时间没有问题的代码中突然发生。

在给定线程中提出的一些建议是:

  1. 关闭连接池,使您的连接字符串看起来像例如"Data Source=Sql2005;Initial Catalog=MyDbName;User Id=MyLogin;Password=MyPass;Pooling=false"(这很可能会影响您的应用程序的性能,但肯定会起作用)
  2. 将所有引用SqlConnection 实例的static 代码重构为non-static
  3. 修复对您的SqlConnections 的可能的多线程访问(这可能不是那么容易...)

我仍在尝试在我们的应用程序中找到错误的根源,但这并不容易,因为我无法在我们的实际环境之外重现它。 Matt Neerincx [MSFT] suggests in one of his answers 在上面提到的帖子中使用不同的连接字符串,从而为应用程序的不同部分使用不同的连接池,以帮助缩小问题的根源。

我在 hibernate 论坛上发现的另一篇关于此问题的文章:https://forum.hibernate.org/viewtopic.php?p=2386963,其中一位发帖人也遇到了多线程场景中延迟加载的问题。

希望这将引导任何人朝着正确的方向进行修复。

奥利弗

附:这是我对Nhibernate FieldNameLookup throws IndexOutOfRangeException的答复的副本

【讨论】:

  • 我认为您的解决方案不仅仅适用于 NHibernate。特别是如果您在使用 AspDotNetStorefront 时遇到问题。
  • 我们使用 UCommerce 和 Umbraco。 UCommerce 使用 NHibernate。我们得到了数千个这样的 IndexOutOfRangeException 错误。将池设置为 false 现在似乎已解决...
【解决方案3】:

当我尝试将空值映射到不可为空的属性(即整数)时出现此错误。确保要么确保 sql 值不可为空,要么只使 c# 属性可为空 (public virtual int? NumberOfPoints { get; set; })

【讨论】:

    【解决方案4】:

    我花了将近 3 年的时间来找出我们系统(不使用 nHibernate)中 GetOrdinal 错误的原因。对我们来说,在我们的连接字符串中添加“Enlist=False”可以让问题完全消失。我们已经从每天大约 160 个错误(主要是 GetOrdinal 错误)增加到昨天的 26 个错误,而且没有一个 GetOrdinal。

    显然 Enlist 参数(默认为 True)告诉 ADO 将连接分组并作为单个事务以原子方式处理它们,但它似乎不起作用。我们的代码中绝对没有事务处理指令,但 ADO 对连接进行分组并导致我们的数据出现意外结果。

    如果您没有在代码中处理 SQL 事务,请尝试此设置,您可能会像我们一样获得积极的结果。

    迈克

    【讨论】:

      【解决方案5】:

      您在映射文件中放置了一个长度=50,您确定数据库列是 varchar(50),如果 NHibernate 获取更长的字符串,它可能会导致您的错误。我通常会忽略长度属性。

      【讨论】:

        【解决方案6】:

        如果列名和 Mapping 属性名不匹配,通常系统会抛出 IndexOutOfRangeException 异常。

        【讨论】:

          【解决方案7】:

          一段时间以来,我一直在为一个非常相似的错误而苦苦挣扎。我从使用 Session.CreateSQLQuery(string) 创建的“本机 SQL”查询中得到错误。我之前使用过类似的查询并取得了很好的成功,但这次的问题是我正在查询一个具有子类的实体类型,并且它们在数据库中被映射为每个类的表。

          我注意到,如果我做一个普通查询,让 NHibernate 生成 SQL,它将包含一个格式为“case when subclass_table.Parent_class_id is not null then 1 when parent_class.Id is not null then 0 end as clazz_"。

          所以,在修复之前,我的查询是这样的:

          SELECT TOP 1 *
          FROM Table WITH (TABLOCKX) 
          WHERE Column = 'Value'
          

          (强制排他表锁定是我首先使用“本机 SQL”进行查询的原因...)

          我所做的只是添加了一个名为“clazz_”的列,它就开始起作用了。在这种情况下,我确信结果不会包含子类的实例,所以我只是将值硬编码为零:

          SELECT TOP 1 *, 0 as clazz_ 
          FROM Table WITH (TABLOCKX) 
          WHERE Column = 'Value'
          

          如果结果可能包含子类的实例,这将更加复杂。那么我可能真的必须包含子类表的左外连接,以及 NHibernate 使用它的 CASE 子句。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-02-21
            • 2023-04-01
            • 1970-01-01
            • 2021-12-19
            • 2013-03-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多