NHibernate System.IndexOutOfRangeException

У меня действительно простой класс, который дает странную ошибку. Класс имеет только 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>();

Ответы

Ответ 1

обычно, когда вы получаете IndexOutOfRangeException в NHibernate, это связано с тем, что вы дважды сопоставляли свойство или сопоставляли два свойства с одним и тем же столбцом. Проверьте имена столбцов.

Возможно, что это происходит случайным образом, потому что конфликт появляется только в определенной совокупности данных.

Ответ 2

Мы - и другие - также имели эту проблему недавно и в прошлом. Похоже, что это связано с многопоточным доступом к потокобезопасному SqlConnection. Следующая статья действительно длинная (!) содержит больше примеров и более подробную информацию по этой проблеме: SQLDataReader.GetOrdinal() редко с IndexOutOfRange. Там bbzippo заявляет:

"Очевидно, что SqlDataReader читает набор результатов, оставшийся от предыдущий запрос, выполненный на том же соединение пару секунд назад."

К сожалению, я не нашел реального объяснения того, почему это исключение возникает внезапно в коде, который работал без проблем в течение некоторого времени.

Некоторые предложения, сделанные в данном потоке:

  • Отключить объединение пулов, чтобы ваша строка подключения выглядела, например, "Data Source=Sql2005;Initial Catalog=MyDbName;User Id=MyLogin;Password=MyPass;Pooling=false" (это, скорее всего, будет означать удар производительности для вашего приложения, но обязательно сработает)
  • Рефакторинг всего static кода, ссылающегося на ваш экземпляр SqlConnection на non-static
  • Исправить возможный многопоточный доступ к вашему SqlConnection (это может быть не так просто...)

Я все еще пытаюсь найти источник ошибки в нашем приложении, но это не так просто, потому что я не смог воспроизвести его вне нашей живой среды. Matt Neerincx [MSFT] предлагает в одном из своих ответов в вышеупомянутом сообщении использовать разные строки подключения и, следовательно, различные пулы подключений для разных частей ваше приложение поможет сузить источник проблемы.

Еще одно чтение, которое я нашел относительно этой проблемы, было на форумах спячки: https://forum.hibernate.org/viewtopic.php?p=2386963, где у одного плаката также были проблемы с ленивой загрузкой в многопоточном сценарии.

Надеюсь, это поможет любому в правильном направлении исправить.

Оливер

P.S. Это копия моего ответа на Nhibernate FieldNameLookup вызывает IndexOutOfRangeException

Ответ 3

Я получил эту ошибку, когда попытался отобразить нулевое значение в свойство, отличное от нуля (т.е. целое число). убедитесь, что либо вы убедитесь, что значение sql не равно NULL, либо просто присваиваете свойство С# null (public virtual int? NumberOfPoints { get; set; })

Ответ 4

Я пробовал почти 3 года отслеживать причины ошибок GetOrdinal в нашей системе (которая не использует nHibernate). Для нас добавление "Enlist = False" к нашим строкам соединения заставило проблему полностью уйти. Мы перешли с примерно 160 ошибок в день (главным образом ошибок GetOrdinal) до 26 ошибок вчера, а не одного GetOrdinal.

По-видимому, аргумент Enlist (который по умолчанию является True) сообщает ADO о необходимости группировать соединения и обрабатывать их атомарно как одну транзакцию, но, похоже, не работает. У нас нет абсолютно никаких правил обработки транзакций в нашем коде, но ADO группирует соединения и вызывает неожиданные результаты в наших данных.

Если вы не обрабатываете транзакции SQL в своем коде, попробуйте этот параметр, и вы можете получить положительные результаты так же, как мы.

Mike

Ответ 5

Вы помещаете в файл сопоставления длину = 50, уверены ли вы, что столбец базы данных является varchar (50), если NHibernate извлекает более длинную строку, это может вызвать вашу ошибку. Обычно я оставляю атрибут длины.

Ответ 6

Обычно система генерирует исключение IndexOutOfRangeException, если имена столбцов и имена свойств Mapping не соответствуют должным образом.

Ответ 7

Я боролся с очень похожей ошибкой в ​​течение некоторого времени. Я получал ошибку из запроса "native SQL", созданного с помощью Session.CreateSQLQuery(string). Ранее я использовал похожие запросы с хорошим успехом, но на этот раз проблема заключалась в том, что я запрашивал тип сущности, который имеет подкласс, и они были сопоставлены как таблица за класс в базе данных.

Я заметил, что если я делаю обычный запрос, позволяя NHibernate генерировать SQL, он будет содержать столбец в формате "случай, когда subclass_table.Parent_class_id не является нулевым, а затем 1, когда parent_class.Id не равен нулю, тогда 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'

Если бы результат мог включать экземпляры подкласса, это было бы более сложным. Тогда мне, вероятно, действительно нужно будет включить левое внешнее соединение для таблицы подкласса, а предложение CASE в том, как NHibernate использует его.