【问题标题】:Nhibernate 2nd level Cache with AliasesToBean transformer带有 AliasesToBean 转换器的 Nhibernate 2 级缓存
【发布时间】:2016-12-09 13:47:26
【问题描述】:

我有一个实体:

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 })

它可以返回和缓存数据,但只能作为元组(对象[])。我没有设法返回 Dto。

这是演示问题的工作示例:github

【问题讨论】:

  • result 是如何声明的?
  • @Andrew Whitaker, resultSalesUnitDto
  • 无法复制 - 使用或不使用 Cacheable()。 NH v4.0.4.4000
  • 我也在使用 NH v4.0.4.4000!能否依赖 Fluent 配置或 CacheProvider?
  • 不知道。如果您可以提供完整的 repro 项目或其他内容(例如 Is it possible to fetch a link table without fetching all links? 帖子中的 OP),将看看发生了什么。

标签: c# caching nhibernate nhibernate-caches resulttransformer


【解决方案1】:

事实证明这是 (N)Hibernate 的一个错误/限制。当缓存被激活时,原始的IResultTransformer 开始接收nullstring[] 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 变体。

【讨论】:

    【解决方案2】:

    NHibernate 的这个 bug 已在 v4.1.0.4000!

    【讨论】:

    • 非常感谢兄弟,你太棒了!
    • 不幸的是,在选定的方言上使用 MaxAliastLength 相互介绍,我与 SQLite 驱动程序的所有集成测试都失败了。 :(
    猜你喜欢
    • 2011-08-15
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 2016-02-13
    • 1970-01-01
    • 2013-02-26
    • 1970-01-01
    • 2011-05-13
    相关资源
    最近更新 更多