Могут ли DTO иметь вложенные DTO? - PullRequest
8 голосов
/ 29 июня 2011

У меня есть следующая модель домена:

public class Playlist
{
    public long Id { get; set; }
    public string Title { get; set; }
    public virtual ICollection<Song> Songs { get; set; }
}

public class Song
{
    public long Id { get; set; }
    public string Name { get; set; }
    public virtual Playlist Playlist { get; set; }
    public virtual ICollection<Catalog> Matches { get; set; }
}

public class Catalog
{
    public long Id { get; set; }
    public string Title { get; set; }
}

Мой сервис имеет следующий код:

public PlaylistResult FindByPlaylistId(long id)
{
    Playlist playlist = playlistRepository.GetById(id);

    foreach (var song in playlist.Songs)
    {
        song.Matches = catalogRepository.GetMatches(song.Name).ToList();
    }

    return new PlaylistResult(new PlaylistDTO(playlist), playlist.Songs.Select(x => new SongDTO(x)));
}

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

Затем данные преобразуются в DTO, добавляются в объект результата и передаются обратно в контроллер.Код выглядит так:

public class PlaylistResult
{
    public PlaylistResult(PlaylistDTO playlist, IEnumerable<SongDTO> songs)
    {
        Playlist = playlist;
        Songs = songs;
    }

    public PlaylistDTO Playlist { get; private set; }

    public IEnumerable<SongDTO> Songs { get; private set; }
}

Проблема:

Объект PlaylistResult до сих пор работал отлично, но недавнее появление совпадений усложнило ситуацию.Похоже, у меня нет другого выбора, кроме как изменить свой SongDTO для учета совпадений и выглядеть так:

public class SongDTO
{
    public SongDTO(Song song, IEnumerable<CatalogDTO> matches)
    {
        Id = song.Id;
        Name = song.Name;
        Matches = matches;
    }

    public long Id { get; private set; }

    public string Name { get; private set; }

    public IEnumerable<CatalogDTO> Matches { get; private set; }
}

Но не противоречит ли это цели DTO?Насколько я понимаю, DTO - это плоское представление данных, и этот подход не сглажен.С другой стороны, я не вижу, как еще это сделать, поскольку каждый матч специфичен для каждой песни.

Я знаю, что мог бы упростить это для себя, выбросить DTO и передать доменМодель к контроллеру напрямую и назовите это день.Но я не хочу этого делать, так как вся цель - научиться работать с DTO.

Любой вклад очень важен.

Ответы [ 2 ]

8 голосов
/ 29 июня 2011

DTO не являются плоским представлением данных, хотя они могут быть.

В этом их прелесть - вы можете структурировать их так, как вам нужно, в отличие от того, как база данных определяет вещи. Также они являются средством отделения данных от поведения.

Я бы вообще не помещал ссылку на объект Domain в DTO. (У вас это есть в конструкторе) Используйте фабрику для создания DTO, чтобы ваши клиенты могли ссылаться только на DTO, а не на объекты Domain.

 Song mySong;
 SongDTO = DTOFactory.GetSong(mySong);

Если вашим клиентам нужно ссылаться на объекты Домена, они могут также использовать их!

0 голосов
/ 30 июня 2011

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

...