Целесообразность использования DTO
Есть сущность бд Student
public class Student
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string FirstName { get; set; }
//Другие свойства
}
В каком-либо классе в методе GetStudents я возвращаю коллекцию Student.
Нужно ли делать отдельный DTO/Poco-класс, если абсолютно все его свойства совпадают? Или же я могу вернуть просто коллекцию Student?
//DTO/Poco класс
public class StudentResponse
{
public int Id { get; set; }
public string FirstName { get; set; }
}
//Класс с расширением для конвертацией без использования AutoMapper
public static class StudentExtensions
{
public static StudentResponse ToResponse(this Student student)
{
return new StudentResponse()
{
Id = student.Id,
FirstName = student.FirstName
};
}
}
Ответы (1 шт):
Если брать стандартное приложение, тут используется одна очень хорошая концепция. Припустим, что у вас приложения состоит из трёх "модулей":
- База данных
- Сервисы (Библиотека либо проект, который занимается основной обработкой данных)
endpoints
Теперь посмотрим на логику, как это всё работает с самого верху. Клиент (Клиентское приложение) делает запрос на endpoint (Либо взаимодействует как-то с UI, если это desktop). Этот запрос формулируется определённым форматом, что бы уточнить, какие данные нужны клиенту. Для примера, для списка продуктов и для детального просмотра какого-то продукта будут использоваться разные запросы, хотя данные вы хотите получить почти одинаковые. Это всё делается при помощи параметров в HttpGet запросе и headers данного запроса. Соответственно, используются различные endpointы.
Далее контроллер, получив запрос, передаст его в сервисы. На этом уровне это должно выглядеть буквально как одва-две строки кода. Буквально, вы вызываете метод сервиса и передаёте туда периметр, а потом анализируете ответ сервиса и делаете соответствующий возврат значения (Если это web-api или ему подобный, там может быть Ok, NoContent, NotFound, BadRequest, InternalServerError и так дале) который зависит от результата обработки сервисов.
На этом уровне мы приходим к одной очень крутой мысли, что наш endpoint общается с сервисами при помощи моделей. Хорошо, а что тогда на уровне сервисов?
При вызове сервисов мы передаём туда некую модель. В зависимости от этой модели, сервис будет делать разную выборку (Это очень важно) в результате какой получит entity (Либо список из entity). Если что (Я не знаю, на сколько вы глубоко это понимаете, entity - это объект базы данных, т.е., уникальная хранящаяся там запись, рекорд и т.д.).
Т.е. тут мы снова понимает, что сервисы общаются с БД при помощи entity. То есть буквально, если мы делаем запись в базу данных, мы туда закидываем entity. Если мы хотим получить что-то из базы данных, мы снова получаем entity. И теперь осталось сделать последний элемент в нашей цепочке.
Я уже выше описал, вы endpoint общается с сервисами при помощи моделей. Исходя отсюда, мы приходим к тому, что для того, что бы мы могли отправить что-то из сервиса на endpoint у нас должна быть модель, т.е., та самая DTO.
Теперь, почему мы должны использовать DTO? В базе данных хранится так называемая чувствительная информация или sensetive data. Получения это информации на клиенте может раскрыть очень много вещей, который вообще по принципу программирования не должны там быть. Это могут быть Id, первичные ключи, внешние ключи и так далее. Для того, что бы такая не случилось, мы используем DTO при описании которой мы сразу исключаем там наличие лишней информации, а записываем туда только то, что нужно клиенту.
Вернёмся к примеру с продуктами. При получении списка продуктов, вы будете делать выборку из таблицы продуктов, но вам не нужно полная информация о продукте, вам нужно, условно, только название, цена, там какой-то shortDescription и всё. Вы получаете список таких продуктов. Когда вы смотрите конкретно какой-то продукт, вы уже можете посмотреть полную информацию: цену, количество покупок, описание, применение, состав, изготовителя, строг годности и много-много другого. Это всё делается на уровне DTO, когда вы описываете ваш DTO класс согласной той информации, которая вам действительное нужна для описания какой-то страницы (Или эта информация нужна другому сервису)