2016-12-09 14 views
2

У меня есть сущность:Nhibernate второго уровня кэша с AliasesToBean трансформатора

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(), я получу исключение:

Сообщение: Значение не может быть равно нулю. Имя параметра: псевдонимами StackTrace:

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

Он может вернуться и кэш данных, но только в качестве кортежей (Object []). Я не смог вернуть Дто.

Вот рабочий пример, чтобы продемонстрировать проблему: github

+0

Как объявляется «результат»? –

+0

@Andrew Whitaker, 'result' is' SalesUnitDto' –

+0

Невозможно воспроизвести - работает с или без 'Cacheable()'. NH v4.0.4.4000 –

ответ

2

Оказывается, чтобы быть ошибка/ограничение (N) Hibernate. Когда кеширование активировано, оригинал IResultTransformer начинает принимать аргумент nullstring[] aliases, что необходимо для реализации AliasToBeanTransformer, следовательно, вы получаете исключение.

В качестве обходного пути я мог бы предложить следующий метод пользовательского расширения и трансформатор, который сохраняет текущие псевдонимы при вызове и передает их в основной AliasToBeanTransformer когда передается аргумент null:

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.

1

Эта ошибка NHibernate фиксируется в v4.1.0.4000!

+0

Спасибо lot bro, ур большой! – vaqifrv

+0

Unfortunatelly вводит друг друга с MaxAliastLength на выбранном диалекте, и все мои тесты интеграции с драйвером SQLite терпят неудачу. :( – dariol