Skip to content

Query cache + entity with Enum id + child collection => NullReferenceException when loading from second level cache #3643

Open
@cwatzl

Description

@cwatzl

After upgrading an old legacy project from NH 5.2.7 to 5.5.2 I encountered a peculiar regression bug:

  • Root Entity has an Id property having an enum type, and a one-to-many relationship with another entity
  • Second level cache and query cache is used for querying the Entity; child collection is fetched eagerly in the query in question
  • First execution of the query (with unpopulated cache) works; subsequent executions fail with NullReferenceException thrown in TypeHelper.

Example model:

	class Entity
	{
		private readonly ICollection<ChildEntity> _children = new List<ChildEntity>();
		public virtual EntityId Id { get; protected set; }
		public virtual IEnumerable<ChildEntity> Children => _children.AsEnumerable();
	}

	class ChildEntity
	{
		public virtual int Id { get; protected set; }
	}

	enum EntityId
	{
		Id1,
		Id2
	}

Mapping:

mapper.Class<Entity>(
	rc =>
	{
		rc.Id(x => x.Id);
		rc.Bag(
			x => x.Children,
			m =>
			{
				m.Access(Accessor.Field);
				m.Key(k => k.Column("EntityId"));
			},
			r => r.OneToMany());
		rc.Cache(
			cm =>
			{
				cm.Include(CacheInclude.All);
				cm.Usage(CacheUsage.ReadWrite);
			});
	});

mapper.Class<ChildEntity>(
	rc =>
	{
		rc.Id(x => x.Id);
		rc.Cache(
			cm =>
			{
				cm.Include(CacheInclude.All);
				cm.Usage(CacheUsage.ReadWrite);
			});
	});

Query:

session
    .Query<Entity>()
    .FetchMany(x => x.Children)
    .WithOptions(opt => opt.SetCacheable(true))
    .ToList();

Exception thrown on second and all subsequent query executions:

NHibernate.Exceptions.GenericADOException : Could not execute query[SQL: SQL not available]
  ----> System.NullReferenceException : Object reference not set to an instance of an object.
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results, Object filterConnection) in C:\dev\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 563
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results) in C:\dev\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 523
   at NHibernate.Impl.AbstractSessionImpl.List[T](IQueryExpression query, QueryParameters parameters) in C:\dev\nhibernate-core\src\NHibernate\Impl\AbstractSessionImpl.cs:line 182
   at NHibernate.Impl.AbstractQueryImpl2.List[T]() in C:\dev\nhibernate-core\src\NHibernate\Impl\AbstractQueryImpl2.cs:line 111
   at NHibernate.Linq.DefaultQueryProvider.ExecuteList[TResult](Expression expression) in C:\dev\nhibernate-core\src\NHibernate\Linq\DefaultQueryProvider.cs:line 111
   at NHibernate.Linq.NhQueryable`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() in C:\dev\nhibernate-core\src\NHibernate\Linq\NhQueryable.cs:line 65
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at NHibernate.Test.NHSpecificTest.GHXXXX.FixtureByCode.LoadEntityByNameWithQueryCache() in C:\dev\nhibernate-core\src\NHibernate.Test\NHSpecificTest\GHXXXX\FixtureByCode.cs:line 108
   at NHibernate.Test.NHSpecificTest.GHXXXX.FixtureByCode.LoadsEntityWithEnumIdAndChildrenUsingQueryCache() in C:\dev\nhibernate-core\src\NHibernate.Test\NHSpecificTest\GHXXXX\FixtureByCode.cs:line 95
--NullReferenceException
   at NHibernate.Type.TypeHelper.InitializeCollections(Object[] cacheRow, Object[] assembleRow, IDictionary`2 collectionIndexes, ISessionImplementor session) in C:\dev\nhibernate-core\src\NHibernate\Type\TypeHelper.cs:line 137
   at NHibernate.Cache.StandardQueryCache.InitializeCollections(ICacheAssembler[] returnTypes, ISessionImplementor session, IList assembleResult, IList cacheResult) in C:\dev\nhibernate-core\src\NHibernate\Cache\StandardQueryCache.cs:line 554
   at NHibernate.Cache.StandardQueryCache.GetResultFromCacheable(QueryKey key, ICacheAssembler[] returnTypes, Boolean isNaturalKeyLookup, ISessionImplementor session, IList cacheable) in C:\dev\nhibernate-core\src\NHibernate\Cache\StandardQueryCache.cs:line 582
   at NHibernate.Cache.StandardQueryCache.Get(QueryKey key, QueryParameters queryParameters, ICacheAssembler[] returnTypes, ISet`1 spaces, ISessionImplementor session) in C:\dev\nhibernate-core\src\NHibernate\Cache\StandardQueryCache.cs:line 147
   at NHibernate.Cache.QueryCacheExtensions.Get(IQueryCache queryCache, QueryKey key, QueryParameters queryParameters, ICacheAssembler[] returnTypes, ISet`1 spaces, ISessionImplementor session) in C:\dev\nhibernate-core\src\NHibernate\Cache\IQueryCache.cs:line 147
   at NHibernate.Loader.Loader.GetResultFromQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IQueryCache queryCache, QueryKey key) in C:\dev\nhibernate-core\src\NHibernate\Loader\Loader.cs:line 1943
   at NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces) in C:\dev\nhibernate-core\src\NHibernate\Loader\Loader.cs:line 1887
   at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces) in C:\dev\nhibernate-core\src\NHibernate\Loader\Loader.cs:line 1842
   at NHibernate.Loader.Hql.QueryLoader.List(ISessionImplementor session, QueryParameters queryParameters) in C:\dev\nhibernate-core\src\NHibernate\Loader\Hql\QueryLoader.cs:line 302
   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) in C:\dev\nhibernate-core\src\NHibernate\Hql\Ast\ANTLR\QueryTranslatorImpl.cs:line 156
   at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) in C:\dev\nhibernate-core\src\NHibernate\Engine\Query\HQLQueryPlan.cs:line 115
   at NHibernate.Impl.SessionImpl.List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results, Object filterConnection) in C:\dev\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 553
[...]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions