-
Notifications
You must be signed in to change notification settings - Fork 932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query cache + entity with Enum id + child collection => NullReferenceException when loading from second level cache #3643
Comments
I did some more digging and somewhat understand the problem now. In var collection = session.PersistenceContext.GetCollection(new CollectionKey(pair.Value, value)); The reason for that, as far as I understand it:
Now I don't really know how to solve this properly, as there are many moving parts involved, and I lack in-depth knowledge of NHiberbernate's internals. I do have an application-side workaround that solves the problem for now in my legacy project, which is to use a custom subclass of mapper.Class<Entity>(
rc =>
{
rc.Id(x => x.Id, x => x.Type<CacheSafeEnumIdType<EntityId>>());
// ... child collection mapping & caching configuration skipped for brevity, no changes to original example ...
}); /// <summary>
/// Workaround for weird NHibernate bug when using an Enum as primary key in combination with 2nd level cache / query cache.
/// See https://github.com/nhibernate/nhibernate-core/issues/3643
/// If that bug gets fixed, this custom type and its usage can be removed.
/// </summary>
class CacheSafeEnumIdType<TEnum> : EnumType<TEnum> where TEnum : Enum
{
public override bool IsEqual(object x, object y)
{
if (ReferenceEquals(x, y) || base.IsEqual(x, y))
{
return true;
}
// Here comes the actual workaround:
// One of the values might be of an integer type, which may be the case
// when it NHibernate is constructing a cache lookup key from a "disassembled" enum value (enums are stored as int in L2C).
if (TryConvertToEnum(x, out var xEnum) && TryConvertToEnum(y, out var yEnum))
{
return xEnum.Equals(yEnum);
}
return false;
}
private static bool TryConvertToEnum(object obj, out TEnum result)
{
switch (obj)
{
case null:
result = default;
return false;
case TEnum @enum:
result = @enum;
return true;
default:
try
{
result = (TEnum)Enum.ToObject(typeof(TEnum), obj);
return true;
}
catch (ArgumentException)
{
result = default;
return false;
}
}
}
} |
After upgrading an old legacy project from NH 5.2.7 to 5.5.2 I encountered a peculiar regression bug:
NullReferenceException
thrown inTypeHelper
.Example model:
Mapping:
Query:
Exception thrown on second and all subsequent query executions:
The text was updated successfully, but these errors were encountered: