带有 AliasesToBean 转换器的 Nhibernate 二级缓存
Nhibernate 2nd level Cache with AliasesToBean transformer
我有一个实体:
public class SalesUnit
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
和相关的Dto:
public class SalesUnitDto
{
public long Id { get; set; }
public string Name { get; set; }
}
我有一个非常简单的查询:
SalesUnitDto result = null;
var list = _session.QueryOver<SalesUnit>()
.SelectList(l => l
.Select(x => x.Id).WithAlias(() => result.Id)
.Select(x => x.Name).WithAlias(() => result.Name))
.TransformUsing(Transformers.AliasToBean<SalesUnitDto>())
//.Cacheable()
.List<SalesUnitDto>();
在我插入二级缓存之前它一直在工作。因此,如果我取消注释 Cacheable()
行,我将得到异常:
消息:值不能为空。参数名称:别名
堆栈跟踪:
at NHibernate.Transform.AliasedTupleSubsetResultTransformer.IncludeInTransform(String[] aliases, Int32 tupleLength)
at NHibernate.Transform.CacheableResultTransformer.Create(ITupleSubsetResultTransformer transformer, String[] aliases, Boolean[] includeInTuple)
at NHibernate.Loader.Loader.GenerateQueryKey(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results)
那有什么问题呢?它是 NHibernate 的错误吗?
我尝试了不同的供应商但无济于事。我还尝试像这样创建 CacheableResultTransformer:
CacheableResultTransformer.Create(Transformers.AliasToBean<SalesUnitDto>(), new[] { "Id", "Name" }, new[] { true, true })
它可以 return 和缓存数据,但只能作为元组 (object[])。我没能 return Dto.
下面是演示问题的工作示例:github
原来是(N)Hibernate的一个bug/limitation。当缓存被激活时,原来的 IResultTransformer
开始接收 null
string[] aliases
参数,这对于 AliasToBeanTransformer
实现是必不可少的,因此你得到了异常。
作为解决方法,我可以建议使用以下自定义扩展方法和转换器,它在调用时存储当前别名,并在传递的参数为 null
时将它们传递给基础 AliasToBeanTransformer
:
public static class NHExtensions
{
public static IQueryOver<TRoot, TSubType> TransformUsingAliasToBean<TRoot, TSubType>(this IQueryOver<TRoot, TSubType> query, Type resultType)
{
ITupleSubsetResultTransformer resultTransformer = new AliasToBeanResultTransformer(resultType);
var criteria = query.UnderlyingCriteria as NHibernate.Impl.CriteriaImpl;
if (criteria != null)
resultTransformer = new CacheableAliasToBeenResultTransformer(resultTransformer, criteria.Projection.Aliases);
return query.TransformUsing(resultTransformer);
}
class CacheableAliasToBeenResultTransformer : ITupleSubsetResultTransformer
{
ITupleSubsetResultTransformer baseTransformer;
string[] aliases;
public CacheableAliasToBeenResultTransformer(ITupleSubsetResultTransformer baseTransformer, string[] aliases)
{
this.baseTransformer = baseTransformer;
this.aliases = aliases;
}
public bool[] IncludeInTransform(string[] aliases, int tupleLength)
{
return baseTransformer.IncludeInTransform(aliases ?? this.aliases, tupleLength);
}
public bool IsTransformedValueATupleElement(string[] aliases, int tupleLength)
{
return baseTransformer.IsTransformedValueATupleElement(aliases ?? this.aliases, tupleLength);
}
public IList TransformList(IList collection)
{
return baseTransformer.TransformList(collection);
}
public object TransformTuple(object[] tuple, string[] aliases)
{
return baseTransformer.TransformTuple(tuple, aliases ?? this.aliases);
}
}
}
你的查询是:
SalesUnitDto result = null;
var list = _session.QueryOver<SalesUnit>()
.SelectList(l => l
.Select(x => x.Id).WithAlias(() => result.Id)
.Select(x => x.Name).WithAlias(() => result.Name))
.TransformUsingAliasToBean(typeof(SalesUnitDto))
.Cacheable()
.List<SalesUnitDto>();
已针对此场景进行测试和工作。当然,我不能保证它适用于所有 QueryOver
变体。
NHibernate 的这个错误在
v4.1.0.4000!
我有一个实体:
public class SalesUnit
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
和相关的Dto:
public class SalesUnitDto
{
public long Id { get; set; }
public string Name { get; set; }
}
我有一个非常简单的查询:
SalesUnitDto result = null;
var list = _session.QueryOver<SalesUnit>()
.SelectList(l => l
.Select(x => x.Id).WithAlias(() => result.Id)
.Select(x => x.Name).WithAlias(() => result.Name))
.TransformUsing(Transformers.AliasToBean<SalesUnitDto>())
//.Cacheable()
.List<SalesUnitDto>();
在我插入二级缓存之前它一直在工作。因此,如果我取消注释 Cacheable()
行,我将得到异常:
消息:值不能为空。参数名称:别名 堆栈跟踪:
at NHibernate.Transform.AliasedTupleSubsetResultTransformer.IncludeInTransform(String[] aliases, Int32 tupleLength)
at NHibernate.Transform.CacheableResultTransformer.Create(ITupleSubsetResultTransformer transformer, String[] aliases, Boolean[] includeInTuple)
at NHibernate.Loader.Loader.GenerateQueryKey(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.ListUsingQueryCache(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results)
那有什么问题呢?它是 NHibernate 的错误吗? 我尝试了不同的供应商但无济于事。我还尝试像这样创建 CacheableResultTransformer:
CacheableResultTransformer.Create(Transformers.AliasToBean<SalesUnitDto>(), new[] { "Id", "Name" }, new[] { true, true })
它可以 return 和缓存数据,但只能作为元组 (object[])。我没能 return Dto.
下面是演示问题的工作示例:github
原来是(N)Hibernate的一个bug/limitation。当缓存被激活时,原来的 IResultTransformer
开始接收 null
string[] aliases
参数,这对于 AliasToBeanTransformer
实现是必不可少的,因此你得到了异常。
作为解决方法,我可以建议使用以下自定义扩展方法和转换器,它在调用时存储当前别名,并在传递的参数为 null
时将它们传递给基础 AliasToBeanTransformer
:
public static class NHExtensions
{
public static IQueryOver<TRoot, TSubType> TransformUsingAliasToBean<TRoot, TSubType>(this IQueryOver<TRoot, TSubType> query, Type resultType)
{
ITupleSubsetResultTransformer resultTransformer = new AliasToBeanResultTransformer(resultType);
var criteria = query.UnderlyingCriteria as NHibernate.Impl.CriteriaImpl;
if (criteria != null)
resultTransformer = new CacheableAliasToBeenResultTransformer(resultTransformer, criteria.Projection.Aliases);
return query.TransformUsing(resultTransformer);
}
class CacheableAliasToBeenResultTransformer : ITupleSubsetResultTransformer
{
ITupleSubsetResultTransformer baseTransformer;
string[] aliases;
public CacheableAliasToBeenResultTransformer(ITupleSubsetResultTransformer baseTransformer, string[] aliases)
{
this.baseTransformer = baseTransformer;
this.aliases = aliases;
}
public bool[] IncludeInTransform(string[] aliases, int tupleLength)
{
return baseTransformer.IncludeInTransform(aliases ?? this.aliases, tupleLength);
}
public bool IsTransformedValueATupleElement(string[] aliases, int tupleLength)
{
return baseTransformer.IsTransformedValueATupleElement(aliases ?? this.aliases, tupleLength);
}
public IList TransformList(IList collection)
{
return baseTransformer.TransformList(collection);
}
public object TransformTuple(object[] tuple, string[] aliases)
{
return baseTransformer.TransformTuple(tuple, aliases ?? this.aliases);
}
}
}
你的查询是:
SalesUnitDto result = null;
var list = _session.QueryOver<SalesUnit>()
.SelectList(l => l
.Select(x => x.Id).WithAlias(() => result.Id)
.Select(x => x.Name).WithAlias(() => result.Name))
.TransformUsingAliasToBean(typeof(SalesUnitDto))
.Cacheable()
.List<SalesUnitDto>();
已针对此场景进行测试和工作。当然,我不能保证它适用于所有 QueryOver
变体。
NHibernate 的这个错误在 v4.1.0.4000!