Свободный NHibernate - ProjectionList - ICriteria возвращает нулевые значения

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

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

Мой домен

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

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

Результат

Но когда я достигаю var managerList, в structList все записи возвращаются из sql, но все с нулевыми значениями, как показано ниже:

После запуска sql запроса

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

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

1 ответ

Решение

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

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). Для связанного дерева ссылок (многие-к-одному) это не сработает. но

II. использовать пользовательский преобразователь результатов

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

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

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

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

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

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

Другие вопросы по тегам