2

Я совершенно новый в NHibernate, но у меня есть googled вокруг и не нашел ничего, чтобы помочь с этой проблемой. Надеюсь, вы, ребята, можете! ;) Я меняю имена свойств и методов, потому что этот код является собственностью компании, но в основном это то, что мне нужно.Fluent NHibernate - ProjectionList - ICriteria возвращает нулевые значения

У меня есть следующий сценарий:

My Domain Entity:

public class Structure 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual Person Manager { get; set; } //I need to fill here. 
    //and others 
} 

Моя карта класса:

public class MapStructure : ClassMap<Structure> 
{ 
    public MapStructure() 
    { 
     Table("TB_Structure"); 
     Id(x => x.Id).Column("Id").GeneratedBy.Identity(); 
     Map(x => x.Name).Column("Name"); 
     References<Person>(x => x.Manager).Column("PersonId").Fetch.Join().NotFound.Ignore(); 
     //... 
    } 
} 

Repository:

public IEnumerable<T> SelectByColumns() 
    { 
     ICriteria searchCriteria = _sessao.CreateCriteria<T>("this"); 

     searchCriteria.CreateAlias("this.Manager", "Manager"); 

     //Only for example purpose. Those columns come as an array string parameter, but the treatment is the same one. 
     var columns = Projections.ProjectionList(); 
     columns.Add(Projections.Property("Manager.Id")); 
     columns.Add(Projections.Property("Manager.Name")); 
     columns.Add(Projections.Property("Manager.Document")); 

     searchCriteria.SetProjection(columns); 
     searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>()); 

     return searchCriteria.List<T>(); 
    } 

И, наконец, вызов:

public IEnumerable<Person> GetManager() 
{ 
    using (IDbSession dbSession = _sessionFactory.Create()) 
    { 
     try 
     { 
      IRepository<Structure> _repository = dbSession.CreateRepository<Structure>(); 
      IEnumerable<Structure> structureList = _repository.SelectByColumns(); 

      var managerList = (from structure in structureList 
           where structure.Manager != null 
           select new Person() 
           { 
            Id = structure.Manager.Id, 
            Name = structure.Manager.Name, 
            Document = structure.Manager.Document 
           }); 

      return managerList.OrderBy(x => x.Name); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
} 

Это создает мне запрос SQL, как показано ниже:

SELECT manager1_.PersonId as y0_, manager1_.Name as y1_, manager1_.Document as y2_ 
FROM TB_Structure this_ 
inner join TB_Person manager1_ on this_.ManagerId=manager1_.PersonId 

И это именно то, что мне нужно. Если я запустил этот запрос в студии управления, я получил все результаты, которые ожидал.

Result

Но когда я достигаю УАК managerList, то structureList есть все записи возвращаются из SQL, но все с нулевыми значениями, как показано ниже:

After run sql query

Я уже судимым с CreateAlias, CreateCriteria, верните IList <>, верните IEnumerable. Я уже изменил Transformers.AliasToBean() на Transformers.AliasToEntityMap. Множество разных вещей, которые я нашел в Google, но у меня всегда был тот же результат.

Я ценю любую помощь и благодарю вас за ваше время!

ответ

2

Вы почти находитесь. Нам нужно правильно преобразовать проекции в дерево сущностей/объектов. Для этого потребуется два шага:

I. использовать псевдоним для каждого столбца

Колонка Алиас, полезно больше для обработки постфактум, чем для генерации оператора SQL. Но это необходимо для следующего шага. Таким образом, вместо этого:

columns.Add(Projections.Property("Manager.Id")); 
columns.Add(Projections.Property("Manager.Name")); 
columns.Add(Projections.Property("Manager.Document")); 

нам это нужно:

columns.Add(Projections.Property("Manager.Id").As("Manager.Id"); 
columns.Add(Projections.Property("Manager.Name").As("Manager.Name")); 
columns.Add(Projections.Property("Manager.Document").As("Manager.Document")); 

На самом деле, это было бы достаточно, если мы используем первый уровень (без JOIN) сущность. Для ссылочного дерева JOINed (много-к-одному) это не сработает. но

II. использование настраиваемого трансформатора результата

Как и всегда, NHibernate предоставляет множество открытых точек для пользовательских расширений. Одним из них будет пользовательский IResultTransformer.Один, готовый для обработки опорного дерева нам нужно здесь:

Имея, что в нашем решении мы должны вместо этого:

searchCriteria.SetResultTransformer(Transformers.AliasToBean<T>()); 

использовать это:

searchCriteria.SetResultTransformer(new DeepTransformer<T>()); 

Эта реализация сильно зависит от настройки правильного псевдонима, descr ibing реальных свойств объекта (использовать отражение, чтобы найти, что установить). Итак, первый пункт - псевдоним столбца/свойства действительно необходим

+0

СПАСИБО ВАМ ТАК БОЛЬШЕ @Radim Köhler! ДЕЙСТВИТЕЛЬНО СДЕЛАЛ НЕДЕЛЬ! –

+0

Замечательно видеть это, сэр! ;) Наслаждайтесь потрясающим NHibernate;) –

+0

Я использую этот DeepTransformer, который вы принимаете, и его невероятно удобно. Итак, в этом вопросе, что вам нужно сделать, если «Менеджер» является нулевым и не существует? По моему опыту репликации этого, если менеджер имеет значение NULL, проекция пропускает все эти строки, и они даже не попадают в результирующий трансформатор. – user99999991

Смежные вопросы