我有以下域模型:
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。
任何意见都将不胜感激。
DTO不是数据的扁平表示,尽管它们可以是。
这就是它们的美妙之处——你可以根据需要构建它们,而不是数据库如何定义事物。此外,它们也是将数据与行为分离的一种手段。
我根本不会在DTO中引用Domain对象。(您在构造函数中有它)使用工厂来构建DTO,这样您的客户端只需要引用DTO,而不需要引用Domain对象。
Song mySong;
SongDTO = DTOFactory.GetSong(mySong);
如果您的客户端需要引用域对象,那么他们也可以使用它们!
您所做的是正确的。我认为,当您向应用程序的数据层传递数据时,它们本质上是扁平表示。