SetCacheable throws IndexOutOfBoundsException - nhibernate

I have following query in NHibernate where the result is a list of DTO's, not entities:
var result = query
//.SetCacheable(true)
.SetResultTransformer(new MyDTOTransformer())
.List<DTO>();
This works with SetCacheable in comment but it throws an IndexOutOfBoundsException when I set SetCacheable to true.
This is the stacktrace:
at NHibernate.Type.TypeFactory.Disassemble(Object[] row, ICacheAssembler[] types, Boolean[] nonCacheable, ISessionImplementor session, Object owner)
at NHibernate.Cache.StandardQueryCache.Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, Boolean isNaturalKeyLookup, ISessionImplementor session)
at NHibernate.Loader.Loader.PutResultInQueryCache(ISessionImplementor session, QueryParameters queryParameters, IType[] resultTypes, IQueryCache queryCache, QueryKey key, IList result)
at NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
at NHibernate.Loader.Custom.CustomLoader.List(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Impl.SessionImpl.ListCustomQuery(ICustomQuery customQuery, QueryParameters queryParameters, IList results)
at NHibernate.Impl.SessionImpl.List(NativeSQLQuerySpecification spec, QueryParameters queryParameters, IList results)
at NHibernate.Impl.SessionImpl.List[T](NativeSQLQuerySpecification spec, QueryParameters queryParameters)
at NHibernate.Impl.SqlQueryImpl.List[T]()
at ...
Can anyone help me and say how I can fix this (or even if this is supported in NHibernate)?
I'm currently using NHibernate-version 2.1.0.4000.
Thank you,
Jelle

I may be mistaken, but I think that the query cache relies on the second level cache being enabled. To be honest, I wonder if it would be all that useful without entity caching in the second level cache, because all the it stores is a list of ID's associated with a given query / parameter combination (you'd still need to go to the database to actually get the objects, and in some situations this could lead to 1 query per object).
This is one of the better posts on caching in nhibernate that I've seen, and it seems to suggest towards the end that you can only cache queries in the second level cache

I had this same exception, and it's fixed now. Yesterday when I used a second cache by setting SetCacheable for my entity, an IndexOutOfBoundsException occurred.
I Googled for it and found a blog that mentioned it may be a problem with my Customer Entity. I tried query.setCacheable(true);, and added query.setCacheMode(CacheMode.GET); and it worked! Give this solution a try.

I think you just need to "declare" your columns that you are returning from your DTO, by using AddScalar. Without the AddScalar lines below (one for each of the columns in your result set) there is no column definition meta-data which the second-level cache code needs (and thus the index out of bounds exception)
Just use AddScalar to list all of your columns being returned and I'll bet it works.
var result = query
//.SetCacheable(true)
.AddScalar("yourfirstcolumn",NHibernateUtil.Int32)
.AddScalar("yoursecondcolumn",NHibernateUtil.String)
.SetResultTransformer(new MyDTOTransformer())
.List<DTO>();

Related

NHibernate: should concurrency issues cause errors in log4net?

I am dealing with concurrency issues in nhibernate and I am not really sure if I am doing right. I use a version field and when the transaction gets comitted, I think an StaleObjectStateException will get thrown if the version field was changed by another process. I catch this exception and handle that case and it seems to work.
But what I am wondering about is, that every time the exception is thrown, NHibernate produces an ERROR in my log4net-Logfile. I have set the loglevel for NHibernate to ERROR because I think that if an error occurs that should interest me. But I am not interested in all the messages about some concurrency conflict, because I don't regard that as an ERROR.
So it might be that I am doing something completely wrong? Is it the right way to deal with concurrency by catching the exception?
update: this is what nhibernate puts in my logfile:
2012-06-21 16:47:30,546 ERROR NHibernate.Event.Default.AbstractFlushingEventListener: Could not synchronize database state with session
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Delta.FollowUp.Model.CFollowUp#60003]
bei NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:Zeile 2780.
bei NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:Zeile 2692.
bei NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:Zeile 3000.
bei NHibernate.Action.EntityUpdateAction.Execute() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Action\EntityUpdateAction.cs:Zeile 79.
bei NHibernate.Engine.ActionQueue.Execute(IExecutable executable) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:Zeile 136.
bei NHibernate.Engine.ActionQueue.ExecuteActions(IList list) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:Zeile 126.
bei NHibernate.Engine.ActionQueue.ExecuteActions() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs:Zeile 170.
bei NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs:Zeile 241.
If you don't want to log NHibernate errors, just remove the logger for NHibernate, set it at the FATAL level, or filter the exceptions somehow.
You can still catch the exception, handle it, rethrow it, log it, whatever.
What you do when there's a concurrency issue depends on the app. In a lot of cases it is sufficient to catch the exception and retry the unit of work - but defining the unit of work is where it can get tricky. Depending on your situation, it might be sufficient to load the entity again and make the changes again and then save it, but that really depends on your application.
Basically that exception means that another thread/process has changed the entity in the database, so you need to now react accordingly. NHibernate is logging it as an error because the use of a version field implies optimistic concurrency where you are assuming that nothing else is going to change the row(s) you're changing, so if something does change one of those rows then you need to handle it.

Nhibernate Flush causing Updates where there should be none

I am using the Repo pattern, and I have set up tests to replicate my a HTTP request coming in and then causing dispose on a unit of work once a test has completed.
It appears that after executing a HQL statement, and then calling displose (which in turn calls flush) that it is causing an update across various elements.
Very bizzare - has anyone come across this before?
Here is my HQL statement and it's execution:
_session.CreateQuery("select distinct t from TaskEntity as t").List<T>()
I've pulled this back to it's simplest form - and note the HQL statement is not directly in the CreateQuery.
Here is the stack trace I am getting:
I
BM.Data.Informix.IfxParameterCollection.b(Int32 A_0)
IBM.Data.Informix.IfxParameterCollection.GetParameter(Int32 index)
System.Data.Common.DbParameterCollection.System.Collections.IList.get_Item(Int32 index)
NHibernate.Type.Int32Type.Set(IDbCommand rs, Object value, Int32 index)
NHibernate.Type.NullableType.NullSafeSet(IDbCommand cmd, Object value, Int32 index)
NHibernate.Type.NullableType.NullSafeSet(IDbCommand st, Object value, Int32 index, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Dehydrate(Object id, Object[] fields, Object rowId, Boolean[] includeProperty, Boolean[][] includeColumns, Int32 table, IDbCommand statement, ISessionImplementor session, Int32 index)
NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session)
NHibernate.Action.EntityUpdateAction.Execute()
NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
NHibernate.Engine.ActionQueue.ExecuteActions()
NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
NHibernate.Impl.SessionImpl.Flush()
Case.Data.SQL.NHibernateUnitOfWork.Dispose() in C:\Projects\Case System\Dev\WorkingBranch\Src\Case.Data.SQL\NHibernateUnitOfWork.cs: line 46
Case.Domain.Tests.TaskServicesTests.TakeDown() in C:\Projects\Case System\Dev\WorkingBranch\Src\Case.Domain.Tests\TaskServicesTests.cs: line 40
I faced a similar problem. I'll first tell you what causes this. When NHibernate fetches an entity from the DB it assigns values to it's props. There are few props that have null values in the DB but are not of Nullable type in the class definition. So NHibernate assigns them a default value eg. 0 for int, DateTime.MinValue for datetime etc. When you call commit on the transaction, NHibernate rechecks the values of properties with DB values and since props which should have had Null values now have a default value, NHibernate thinks that the values have been changed and causes an update.
Solution:
Use nullable datatypes for your class props by post fixing them with
? but for me this is causing other problems.
Map your properties as Not Null Types but this is not preferable in
most cases.
The solution that I am using: I am assigning default values to the
props in the entity's constructor, so instead of saving Null values
in the Db Nhibernate saves some default value and this stops the
calls to unnecessary updates.
You may further google NHibernate ghostbuster for more research on this problem.
NHibernate typically runs updates when it has transient or detached entities that it isn't sure about. That is, entities that it doesn't know if it has a parent for that manages it or if its not sure the entity is dirty. This is typically a symptom of a bad mapping somewhere (a missing Inverse on some parent) or you have no Version or Date column on your entities.

Using ODP.Net with NHibernate with .net System.decimal

I am using ODP.net to run the aggregate AVG against an Oracle 10g database. I run this query directly on the database and it works fine:
select avg(ANSCHAFFUNGSKST) from IHObjekt
it returns: 13.4493973163521
Niether the HQL nor the CreateCriteria interfaces successfully execute the query. I recieve an NHibernate 'could not execute query' message. However, I am relatively certain it is an ODP.Net error based on this posting.
There is a solution for Oracle, simply TRUNC the AVG. However, the TRUNC command is different in Oracle versus SQL Server and I need/want to keep my code from being database specific.
Any ideas about how I can reduce the number of decimal points so it fits within a decimal and most importantly, it works on all databases?
Source = NHibernate
StackTrace
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(String query, QueryParameters parameters)
NHibernate.Impl.QueryImpl.List()
DBTest_NHibernate.MainWindow.ButtonHQLQuery_Click(Object sender, RoutedEventArgs e) in C:\...
InnerException
[System.OverflowException] = {"Die arithmetische Operation hat einen Überlauf verursacht."} ... The arithmetic operation has caused an overflow.
Source = Oracle.DataAccess
StackTrace
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 index)
NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name)
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 hydratedObjects, EntityKey[] keys, 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)
Some HQL Testing Results
select TRUNC(AVG(ANSCHAFFUNGSKST),27) from IHObjekt - WORKS (ONLY IN ORACLE)
select TRUNC(AVG(ANSCHAFFUNGSKST),28) from IHObjekt - DOES NOT WORK
select AVG(ANSCHAFFUNGSKST) from IHObjekt - DOES NOT WORK
NHibernate Generated 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_
Only AVG does not work in the above SQL statement on Oracle using ODP.Net. Using SQL Server or the Oracle client it works.
By dissecting the code I was given and cutting it into smaller pieces I can confirm, that you will run into problems when using doubles with excessive amounts of digits right of the comma.
In contrast to the OP, TRUNC(AVG(XXXX)) did not work in my case. However:
TRUNC(doubledigit, intvalue) and ROUND(doubledigit, intvalue)
brought a solution. I tested this with nhibernate and a simple OracleDataReader using odp.net
The issue is due to the value being returned will not cast to a .Net Decimal due to the number of values after the decimal point. It seems that even though the value is rounded by .Net, Oracle internally throw an overflow exception.
Frm what I have read Oracle have confirmed this is by design and won't be changed.
Some people are using Trunc or catsing to a string then a double to get round the issue.

Using a stored procedure and NHibernate to insert a record

Normally the parameterized SQL works great for CRUD, but I have one instance where I want to use a stored procedure to do an insert.
My HBM file has the following (along with a bunch of other properties, bags, etc)
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="MyProject.Entities" assembly="MyProject">
<class name="MyProject.Entities.Policy, MyProject" table="dbo.Policy" lazy="true">
<id name="Id" column="[PolicyId]">
<generator class="native" />
</id>
<sql-insert>exec spInsertPolicy ?,?,?,?,?,?,?</sql-insert>
</class>
</hibernate-mapping>
The number of question marks in the sql-insert matches the number of properties and many-to-one relationships (there isn't a question mark for the Id).
I'm getting the following exception. If I switch the generator to "increment" it works, but I don't want to do that because other processes are permitted to save to the database.
NHibernate.HibernateException: The database returned no natively generated identity value
at NHibernate.Id.IdentifierGeneratorFactory.GetGeneratedIdentity(IDataReader rs, IType type, ISessionImplementor session)
at NHibernate.Id.IdentityGenerator.InsertSelectDelegate.ExecuteAndExtract(IDbCommand insert, ISessionImplementor session)
at NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder)
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Boolean[] notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session)
at NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Object obj, ISessionImplementor session)
at NHibernate.Action.EntityIdentityInsertAction.Execute()
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
at NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
Any suggestions? Thanks.
The stored procedure has to return the generated ID for the inserted record, i.e. a SELECT SCOPE_IDENTITY() at the end of the sproc if you're using SQL Server.

NHibernate System.IndexOutOfRangeException

I've got a really simple class that is giving a strange error. The class only has 1 property and the query is really simple. The stranglest part is that this seems to happen randomly. After getting this error usually refreshing the page makes it go a way and the application doesn't get the errror again.
Could this be a problem with the database connection?
I'm getting:
[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
Here is my class
public class Department : IObject {
public virtual string Name { get; set; }
}
The hbm file
<?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>
and here is the HQL query
var hql = "from Department d where d.Name like 'CBS - %'";
_session.CreateQuery(hql).List<T>();
usually, when you get an IndexOutOfRangeException in NHibernate it is because you mapped a property twice, or mapped two properties to the same column. Check the column names.
It's possible that it occurs randomly because the conflict only shows up in a certain data constellation.
We - and others - have also had this problem recently and in the past. It seems to be related to multi-threaded access to the non-thread-safe SqlConnection. The following really long (!) post contains more examples and some more detail on the issue: SQLDataReader.GetOrdinal() fails rarely with IndexOutOfRange. There bbzippo states:
"It's evident that SqlDataReader reads
a result set left over from the
previous query executed on the same
connection a couple of seconds ago."
Unfortunately, I haven't found any real explanation of why this exception occurs suddenly in code that has been working without a problem for some time.
Some of the suggestions made in the given thread are:
Turn connection pooling off, so your connection string would look like e.g. "Data Source=Sql2005;Initial Catalog=MyDbName;User Id=MyLogin;Password=MyPass;Pooling=false" (this most likely will mean a performance hit for your application but is sure to work)
Refactor all static code referencing your SqlConnection instance(s) to non-static
Fix possible multi-threaded access to your SqlConnections (this might not be that easy...)
I'm still trying to find the source of the error in our application but it's not that easy because I haven't been able to reproduce it outside our live environment. Matt Neerincx [MSFT] suggests in one of his answers in the above mentioned post to use different connection strings and thus different connection pools for different parts of your application to help narrow down the source of the problem.
Another read I found regarding this problem was on the hibernate forums: https://forum.hibernate.org/viewtopic.php?p=2386963, where one poster also had problems with lazy-loading in a multi-threaded scenario.
Hope this will guide anyone in the right direction for a fix.
Oliver
P.S. This is a copy of my answer to Nhibernate FieldNameLookup throws IndexOutOfRangeException
I've gotten this error when I tried to map a null value to a non-nullable property (i.e. an integer). make sure that either you make sure that the sql value is non-nullable, or just make the c# property nullable (public virtual int? NumberOfPoints { get; set; })
I tried for nearly 3 years to track down the cause of GetOrdinal errors in our system (which does not use nHibernate). For us, adding "Enlist=False" to our connection strings made the problem go away completely. We've gone from about 160 errors per day (mostly GetOrdinal errors) to 26 errors yesterday, and not a single GetOrdinal.
Apparently the Enlist argument (which is True by default) tells ADO to group connections and handle them atomically as a single transaction, but it doesn't seem to work. We have absolutely no transaction-handling directives in our code, yet ADO was grouping connections and causing unexpected results in our data.
If you're not handling SQL transactions in your code, try this setting and you may get positive results just like we did.
Mike
You've put a length=50 in the mapping file, are you sure the database column is varchar(50), if NHibernate fetches a longer string it could be causing your error. I would usually leave the length attribute out.
Usually system throws IndexOutOfRangeException exception if the columns names and Mapping property names are not matched properly.
I struggled with a very similar error for some time. I was getting the error from a "native SQL" query, created with the Session.CreateSQLQuery(string). I had used similar queries with good success before, but this time the problem was that I was querying for an entity type that does have a subclass, and they were mapped as table-per-class in the database.
I noticed that if I do a normal query, letting NHibernate generate the SQL, it will include a column in the format like "case when subclass_table.Parent_class_id is not null then 1 when parent_class.Id is not null then 0 end as clazz_".
So, before the fix my query was something like this:
SELECT TOP 1 *
FROM Table WITH (TABLOCKX)
WHERE Column = 'Value'
(Forcing the exclusive table lock is the reason I'm doing the query with the "native SQL" in the first place...)
What I did was just add a column called "clazz_", and it started to work. In this case I KNOW for sure that the results will not include instances of the subclass, so I'm just hard-coding the value as zero:
SELECT TOP 1 *, 0 as clazz_
FROM Table WITH (TABLOCKX)
WHERE Column = 'Value'
If it would be possible for the result to include instances of the subclass, this would be more complicated. Then I would probably really have to include the left outer join for the subclass's table, and the CASE clause in the way NHibernate uses it.