NHibernate объединить 2 таблицы и проект в DTO с коллекцией - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь объединить 2 таблицы и проецировать их напрямую в DTO (NHibernate 5).У меня есть следующие объекты:

public class Person {
    public Guid Id {get;set;}
    public string Name {get;set;}
}

public class Car {
    public Guid Id {get;set;}
    public string Brand {get;set;}
    public Person Owner {get;set;} 
}

, как мы видим, есть просто ссылка от автомобиля к человеку (автомобиль знает своего владельца), и это нормально для всего моего проекта.

Однако,есть одно место, где мне нужно опросить всех людей и собрать каждого человека с коллекцией принадлежащих ему автомобилей.

Я создал такие DTO:

public class PersonDto {
    public Guid Id {get;set;}
    public string Name {get;set;}
    public IList<CarDto> {get;set;}
}

public class CarDto {
    public Guid Id {get;set;}
    public string Brand {get;set;}
}

это своего рода представление данныхсвязаны друг с другом с ног на голову.Эта задача кажется тривиальной с использованием SQL или LINQ (GroupJoin), однако я нашел ее чрезвычайно сложной в NH, поскольку GroupJoin не реализована в NH.

Не могли бы вы помочь мне решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Я бы хотел ответить на свой вопрос.Спасибо Рафаль Рутковски за его ввод.

Чтобы получить данные, которые связаны только в 1 направлении, нам нужно ввести новую модель данных, а затем вручную преобразовать результат в наши объекты.Я надеюсь, что следующий пример является наилучшим возможным ответом:

1) создайте такую ​​модель данных для хранения ответа NH:

private class PersonCarModelDto
{
    public Guid PersonId { get; set; }
    public string PersonName { get; set; }
    public Guid CarId { get; set; }
    public string CarBrand { get; set; }
}

2) создайте такую ​​модель для хранения иерархических данных в качестве вывода:

private class PersonModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public IList<CarModel> Cars { get; set; }
}

private class CarModel
{
    public Guid Id { get; set; }
    public string Brand { get; set; }
}

3) теперь запрос NH:

Person personAlias = null;
Car carAlias = null;
PersonCarModelDto resultAlias = null;

var response = GetCurrentSession().QueryOver<Car>(() => carAlias) // notice we are going from from 'downside' entity to 'up'
    .Right.JoinAlias(c => c.Owner, () => personAlias) // notice Right join here, to have also Persons without any car
    .SelectList(list => list
        .Select(() => personAlias.Id).WithAlias(() => resultAlias.PersonId)
        .Select(() => personAlias.Name).WithAlias(() => resultAlias.PersonName)
        .Select(() => carAlias.Id).WithAlias(() => resultAlias.CarId)
        .Select(() => carAlias.Brand).WithAlias(() => resultAlias.CarBrand)
    .TransformUsing(Transformers.AliasToBean<PersonCarModelDto>())
    .List<PersonCarModelDto>()
    ;

4) теперь у нас есть плоские данные в виде списка PersonCarModelDto, но мы хотим сделать выходную модель:

var modelResult = response.GroupBy(p => p.PersonId)
    .Select(x => new PersonModel
    {
        Id = x.Key,
        Name = x.Select(y => y.PersonName).First(), // First() because each PersonName in that group is the same
        Cars = x.Select(y => new CarModel
        {
            Id = y.CarId,
            Name = y.CarBrand
        })
        .ToList()
    })
    .ToList()
    ;

Выводы:

  • проблему гораздо проще решить с помощью двунаправленных ассоциаций
  • , если по какой-то причине вам не нужны двунаправленные ассоциации, используйтеэтот метод
  • этот подход также полезен, если у ваших сущностей есть много других свойств, но по какой-то причине вам нужна только небольшая их часть (оптимизация данных, возвращаемых для БД)
0 голосов
/ 24 октября 2018

Просто добавьте коллекцию Car к существующему объекту Person и пометьте коллекцию как обратную .Коллекции в NHibernate по умолчанию ленивы, поэтому, когда вы запрашиваете Person, он не будет читать автомобили из БД, пока вы не начнете их перебирать.Другими словами, добавление коллекции Car не повлияет на работу вашего кода.

Если вы хотите эффективно запрашивать людей вместе с автомобилями, заставьте NH выполнить объединение

.QueryOver<Person>.Fetch(person => person.Cars).Eager
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...