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 использует его.