MediatR + CQRS - использование паттернов для разделения запросов и модификаций

Поделиться
HTML-код
  • Опубликовано: 7 июн 2021
  • Разработка ASP NET Core Web API с нуля профессионально. Видео 5. MediatR и CQRS
    В этом видео мы узнаем о паттерне посредник, паттерне CQRS, библиотеке MediatR и продолжим разрабатывать Application уровень приложения.
    Мы в Telegram: t.me/platinum_tech_talks
    Чат для общения и вопросов: t.me/platinum_chat
    Код из видео: github.com/andreisfedotov/Not...
    Видео про Cancellation token: • Собеседование .NET 202...
    People vector created by vectorjuice: www.freepik.com/vectors/people

Комментарии • 110

  • @karmraks
    @karmraks 2 года назад +3

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

  • @metlic5209
    @metlic5209 3 года назад +18

    2:06 чем аргументируется "доведение производительности приложения до максимума"? Медиатр наоборот добавляет оверхед связанный с построением цепочки обработки реквеста. Если имеется ввиду разделение на read-write хранилища, то это из другой темы...
    Опять же не раскрыто зачем это нужно. Перед людьми, которые впервые слышат про CQRS и видя приведенный в видео код, встанет вопрос: "Чем это лучше CRUD-сервиса". Другие же, насмотревшись подобных уроков, пойдут распространять "Культ Карго" не понимая до конца use-case'ов при которых нужно использовать подобные паттерны.
    11:00 зачем было каждое проперти из одного класса маппить вручную на другой, когда либой это все решается (можно опять обратиться к статье Богарда)? Ну и встает дискуссионный вопрос относительно необходимости интерфейса `IMapWith`, поскольку, как мне кажется это смешение инфраструктурного слоя с аппликационным и засорение DTO лишними деталями.

    • @daniilevsienko4060
      @daniilevsienko4060 Месяц назад

      Ничего не сказала рыбка, лишь хвостом по воде плеснула...))

  • @winstochurgle9133
    @winstochurgle9133 Год назад +4

    Да, а я думал, что здесь научат))
    В итоге сижу на десяти страницах и мониторю каждую технологию)

  • @Ayub_Yaqub
    @Ayub_Yaqub 3 года назад +1

    Отлично!
    И шрифт большой .
    Спасибо

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад

      Спасибо вам!
      п.с. вот теперь уже сообразили про шрифты =D

  • @krahmaletskrakmalets7587
    @krahmaletskrakmalets7587 2 года назад +15

    Без преувеличения - у Вас одни из лучших IT-видео на рутубе!

  • @daukaevk
    @daukaevk Месяц назад

    Огромное спасибо! Наконец то понятно!

  • @alexanderspiegel6747
    @alexanderspiegel6747 3 года назад +3

    Пару комментариев / вопросов:
    1. Приятный голос и большие шрифты - то что нужно!
    2. Ждем видео про DI.
    3. Валидаторы появятся в проекте позже ?
    4. Automapper прекрасно справляется если названия и классы полей совпадают. Зачем Вы прописывали маппинг для всех полей ? Для наглядности ?
    5. Где-то можно будет скачать исходный код решения ?
    Поставил лайк за Ваше видео. Спасибо Вам!

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад +3

      1. Спасибо!!!!
      3. Да, валидацию мы добавим немного позже
      4. Вы правы. в Automapper можно использовать соглашения (следовало упомянуть об их существовании в видео). Но чтобы их использовать нужна определенная квалификация. тут в целом могут возникать потенциальные проблемы. например если возникнет ошибка и ее нужно будет исправлять то тому человеку, кому выпадет это удовольствие также нужно будет обладать квалификацией о соглашениях. а тут мы один раз их прописали и если что то сразу видно что конкретно с чем маппится. но в целом да, соглашения Automapper'а - это очень мощная и крутая вещь.
      5. Да, конечно, можно будет взять полный код всего того, что происходит на экране

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад

      5. под каждым видео теперь добавлены ссылки на код из видео

  • @yari_la
    @yari_la 4 месяца назад

    хороший пример, мне понравился CQRS

  • @BraentR
    @BraentR 2 года назад

    Спасибо

  • @Desu_Desu
    @Desu_Desu 2 года назад +5

    Ох, я только с маппингами разобрался, а теперь еще и медиатр и cqrs, удивительно, как я почти прошел собеседование пару лет назад не зная всего этого, знал только crud (Не попал только из-за проблем с военкоматом).
    Сейчас буду куда более готовым, спасибо за курс.

    • @PlatinumTechTalks
      @PlatinumTechTalks  2 года назад

      Спасибо! Удачи вам!

    • @winstochurgle9133
      @winstochurgle9133 Год назад +1

      Ну как успехи? Осилил? Я сейчас на этом этапе :)

    • @hiryu70
      @hiryu70 Год назад +1

      @@winstochurgle9133 ну как осилил?)

    • @winstochurgle9133
      @winstochurgle9133 Год назад

      @@hiryu70 Разумеется :)

    • @hiryu70
      @hiryu70 Год назад

      @@winstochurgle9133 где и над чем работаешь?)

  • @user-bb2ho4ip8t
    @user-bb2ho4ip8t Год назад +8

    в 12 версии MediatR return Unit.Value; при IRequestHandler или IRequestHandler не прокатит, типы не совпадают
    чтобы повторять за автором устанавливайте 9 версию

    • @kirillkhlopkoff252
      @kirillkhlopkoff252 Год назад +1

      Спасибо, кстати, а с чем это связанно конкретно?

    • @user-bb2ho4ip8t
      @user-bb2ho4ip8t Год назад +1

      @@kirillkhlopkoff252 как любят зачастую сделать опцию, потом переименовать, убрать, передумать в новых версиях это рабочие моменты, хотя должна быть обратная совместимость и из новых версий доступны все опции старых

    • @anshe2676
      @anshe2676 Год назад +4

      просидел с этим пару часов, пытаясь разобраться: "почему не работает?".
      в итоге пришел к этому.
      public async Task Handle(UpdateNoteCommand request, CancellationToken cancellationToken)
      {
      var entity = await _dbContext.Notes.FirstOrDefaultAsync(note => note.Id == request.Id, cancellationToken);

      if (entity == null || entity.Id != request.UserId)
      {
      throw new NotFoundException (nameof(Note), request.Id);
      }

      entity.Details = request.Details;
      entity.Title = request.Title;
      entity.EditDate = DateTime.Now;

      await _dbContext.SaveChangesAsync(cancellationToken);
      }
      компилятор не ругается, но допустимо ли это решение? или отсутствие возвращаемого типа мне боком выйдет? пишу вслепую осваивая правильный подход к написанию программ, поэтому зачастую не понимаю что делаю. хочу шпаргалку замутить просто, правильную и работоспособную. отсюда и вопрос

    • @user-lj7uj9ee2f
      @user-lj7uj9ee2f 4 месяца назад +1

      Для того чтобы код работал не обязательно откатывать до 9 версии как автор данного видео, можно откатить до 11.1.0(это максимально рабочая версия, более новые уже не работают)

  • @antya1126
    @antya1126 Месяц назад

    Прекрасный курс. Было бы интересно также разбор архитектурных паттернов, то как вы это видите. Я прошел курс Нестерука по паттернам проектирования, тоже прекрасный курс. С вашим подходом, я думаю будет круто. Ну или часто используемые паттерны разобрать для начала в рамках чистой архитектуры. Кроме cqrs, mediatr...

  • @duming3076
    @duming3076 2 года назад +1

    thx

  • @Eugene.g
    @Eugene.g 3 года назад +11

    удобно вкладывать класс Handler в класс команды/запроса т.к они друг без друга не имеют смысла, валидатор можно туда же. Таким образом отдельные папки не нужны и значительно меньше навигации по файлам
    зачем, кстати, вручную прописывать маппинги? оно же там само маппится по конвенции
    в целом, конечно, море копипасты с этим CQRS

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад +10

      насчет вкладывания одних классов в другие - это конечно от подхода зависит. но мы в целом не любим такой подход. считаем, что классы должны быть простыми и в идеале не большими. а то, что там папки - вроде это не составляет проблемы, а привносит структуру :) в общем, тут на вкус и цвет
      насчет маппингов. да, в Automapper можно использовать кучу соглашений (следовало упомянуть об их существовании в видео). однако чтобы их использовать нужна определенная квалификация. тут есть несколько потенциальных проблем. если возникнет ошибка и ее нужно будет исправлять то тому человеку, кому выпадет это удовольствие также нужно будет обладать квалификацией о соглашениях. а тут мы один раз их прописали и если что то сразу видно что конкретно с чем маппится.
      но в целом да, конвенции - это очень мощная и крутая вещь!
      Спасибо вам за обратную связь!!

  • @nickolayarbuzov6149
    @nickolayarbuzov6149 Год назад

    спасибо большое за видео ! )
    mediatR - это что-то типа на событийную шину похоже, или rxjs; т.е. если все сущности будут общаться через mediatR, то инжектирование классов может не понадобиться ?

  • @Azbdsx
    @Azbdsx 2 года назад

    Доброго времени суток. Такой вопрос. Можно ли добавить референс на проект апликэшн в клиентскую часть (фронт) на пример в блэзор проект, что бы использовать команды как запросы, а вью модели как ответы? И как вообще архитектура cqrc наклыдывается на REST? Или может наоборот следует создать отдельно запросы и ответы в домэйне и уже с них мапиться на команды и вьюмодели? В общем смысл вопроса сводится к одному как не копипастить классы запросов-ответов в клиентской части?

  • @elijahzabrodskyi8545
    @elijahzabrodskyi8545 Год назад

    Относительно AddAsync из доки:
    Этот метод является асинхронным, чтобы разрешить специальные генераторы значений, такие как microsoft.EntityFrameworkCore.Metadata.SqlServerValueGenerationStrategy.SequenceHiLo, для асинхронного доступа к базе данных. Во всех остальных случаях следует использовать несинхронный метод.

  • @abai8955
    @abai8955 2 года назад

    Видео супер! А как поменять отображение != в visual studio?))

  • @caenumplatearum7417
    @caenumplatearum7417 Год назад

    Такой вопрос: как правильно сделать маппинг, если есть классы-сущности Parent и Child, у Parent есть List Childs, и мне нужно сделать ParentViewModel таким, чтобы там был List, полученный из List от Parent. Как это лучше прописать в методе Mapping класса ParentViewModel, можно ли обойтись без Select в options вызова ForMember, и если нельзя, то как обратиться к mapper внутри этого Select (достаточно ли внедрить IMapper в ParentViewModel через конструктор, или это так не работает)?

  • @redice8928
    @redice8928 Год назад

    А как это вы вернули Task в UpdateNoteCommandHandler? Там же void?

  • @vladoss4643
    @vladoss4643 Год назад +1

    Было бы очень интересно посмотреть, как этим люди пользуются. И как это работает своими глазами.
    Потому что так, вроде бы кратко. Вроде бы интересно и работает. Но непонятно

  • @yava43
    @yava43 2 месяца назад +2

    мы для получения 1 сущности создали кучу папок и кучу обработчиков. Неужели нельзя просто вытащить -> замапить -> получить?

  • @edge-of-the-world
    @edge-of-the-world 3 года назад +2

    1) Насчет Dto и Vm... Почему их назвали по разному? В каких случаях стоит именовать их тем или иным образом? Если например NoteVm на клиентской стороне будет использоваться в одном случае как часть другой ViewModel, а в другом как отдельная ViewModel. Как правильно именовать их в этом случае?
    2) Если entity подразумевает наследование, например Note - базовый класс, от которого происходят штук 12 классов наследников с разными свойствами, то как правильно поступать в этом случае с командами на Update и Create? Создавать на каждый класс наследник отдельную команду или одна команда где содержатся все возможные свойства для всех наследников?

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад +1

      1) У нас одни и те же данные имеют разные представления. Для того чтобы не было путаницы с именами (мы можем классы с одним и тем же именем определить в разных сборках) мы решаем их называть по разному. И у нас появляются суффиксы, как соглашение. Тут просто логическое разделение - данные и представление.
      Ключевой момент тут - это соглашение, принятое на проекте. Оно может быть вообще любым (обоснованно конечно и понятно членам команды). С другой стороны конечно лучше использовать популярные соглашения.
      2) Если у нас есть иерархия, то мы можем просто сделать параллельную иерархию команд. Сделать общую команду и наследников.
      Тут нужно понимать контекст, как оно хранится в хранилище. Т.е. если мы обрабатываем каждый подтип отдельно, то и проблемы в создании нескольких классов нет

  • @smookkee1
    @smookkee1 Год назад +3

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

  • @nikolay4362
    @nikolay4362 7 месяцев назад +1

    тутор закончился очень внезапно)

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 месяца назад

      там же продолжение в других видео плейлиста есть)

  • @alexandrsharp920
    @alexandrsharp920 2 года назад +1

    а как из избавиться от Boilerplate code в командах ?

  • @lkn1ghtl
    @lkn1ghtl Год назад

    А можно узнать что делает .ProjectTo(_mapper.ConfigurationProvider)?

  • @alexandr1408
    @alexandr1408 3 года назад

    Это получается, каждый запрос с апи у нас будет соответствовать одному отдельному классу? Т.е в более "классическом" виде, к примеру, у нас был бы какой-нибудь один контроллер Notes, и в нем было бы множество апи-методов GetOne, GetAll и т.п., каждый из которых = отдельному запросу А здесь: отдельный запрос = отдельному классу. Так? Если так, то не будет ли издишнее раздувание количества классов?

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад

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

  • @redice8928
    @redice8928 Год назад +1

    А как настроить такие же стрелочки и операторы сравнения в райдере?

  • @kirillkislov2681
    @kirillkislov2681 Год назад +2

    Разве не проще профаил файлы просто прописывать и все мапы там настраивать, и никаких интерфейсов IMapWith, тогда все модельки анемичные получаются и без привязки к мапперу, а в конфигурации использовать добавление профаил классов с generic версией метода. Возможно я что то не понял

  • @user-xt9dx6rj9q
    @user-xt9dx6rj9q 2 года назад +1

    Привет. У меня id прописаны не guid, a int. Как заменить эту строку Id = Guid.NewGuid() на такую же, только для инта? 5:40

    • @fred20659
      @fred20659 2 года назад

      может в Notes.Domain в классе Notes добавить под Id атрибут [DatabaseGenerated(DatabaseGeneratedOption.Identity)], но я точно не уверен...

  • @ziegimondvishneuski3317
    @ziegimondvishneuski3317 9 месяцев назад

    у меня есть вопрос. как работать с маппингом когда нужно из двух или более Entity-таблиц получить данные, которые должны быть замеппены к одному выходному типу к примеру: User, Person, Address, и Conact данные человека

    • @yava43
      @yava43 2 месяца назад

      мапать вручную =)

  • @romangromov7606
    @romangromov7606 2 года назад +1

    Что-то не могу понять: По заявленному ранее, в философии CQRS, Есть запросы (не меняют состояние системы) и команды (меняют состояние системы).
    Описанные модули UpdateCommand и DeleteCommand - очевидно меняют состояние системы, но наследуются от IRequest.
    Как жить дальше? 🙂

    • @PlatinumTechTalks
      @PlatinumTechTalks  2 года назад

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

    • @user-vh6wy7yj1o
      @user-vh6wy7yj1o 2 года назад

      @@PlatinumTechTalks Тоже это заметил, можете подсказать интерфейс для command, ICommand и ICommand нет.
      Возможно я что-то не понял, прошу разъяснения.

    • @alewarten
      @alewarten Год назад

      Все правильно. В библиотеке Mediatr при создании Command или Query используется IRequest.

    • @romangromov7606
      @romangromov7606 Год назад

      @@alewarten то, что используется - вижу. Я указал на противоречие философии и практики.

    • @Fikusiklol
      @Fikusiklol Год назад +1

      @@romangromov7606 Есть слова Query и Request. Посмотрите определение и станет понятно. Все Command/Query - это запросы (request).
      А обработчики запросов, вне зависимости меняют ли они данные или нет, уже Request (запрос) Handler (обработчик).
      Мб станет понятнее, если правильно уловил суть вопроса вашего.

  • @yuryermolov13
    @yuryermolov13 3 месяца назад

    По коду непонятно зачем вы настраиваете ForMemeber для AutoMapper если все поля имеют одинаковый тип и названия.

  • @user-fb6hs6rd8j
    @user-fb6hs6rd8j 7 месяцев назад +2

    Какая разница между ViewModel и Dto?

    • @user-we6wp1ky7f
      @user-we6wp1ky7f Месяц назад

      Никакой, насколько я понимаю. Вью моделью принято называть дтошки презентайшенал лэйера, т.е. то что возвращается юзеру в респонсе веб апишки или что уходит во вьюшку в mvc.

  • @74Photon
    @74Photon Год назад +2

    11:39 Очень странно это выглядит - автомаппер может смапить эти два класса сам без дополнительного расписывания ForMember
    Да и вообще вся работа с Автомаппером уж сильно усложнена для такого простого приложения.
    Признавайтесь - по какой книге все это написано? :-)

    • @PlatinumTechTalks
      @PlatinumTechTalks  Год назад +1

      скорее всего такая книга еще не написана =)

    • @dgdarkking266
      @dgdarkking266 Год назад

      Я тут погуглил по интернету и у многих есть вопрос как юзать такую реализацию маппинга IMapWith
      Сам знаю, что при одинаковых именах маппинг идёт самостоятельно, но IMapWith использует интерфейс по умолчанию (тут было у меня некоторое не знание)
      Интерфейсы по умолчанию не могут вызываться, если мы работаем с Типом на класс, а не на этот интерфейс
      Получается чтобы использовать этот интерфейс на не достаточно унаследоваться от него, а всё равно надо переопределить метод Mapping для создания профиля

  • @yava43
    @yava43 2 месяца назад

    а если сущностей очень много, это для каждой сущности это всё прописывать ??!!

  • @scc-6
    @scc-6 10 месяцев назад

    Хотел изучить именно АСП кор, он тут будет? Или он уже где-то был, и я пропустил?..

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 месяца назад

      очень поздний ответ, но все же.. вы нашли асп кор в итоге?

    • @scc-6
      @scc-6 3 месяца назад

      @@PlatinumTechTalks Да, спасибо. У вас классная архитектура. Но без знания именно Асп было тяжко, раз по 5 пересматривал. У вас приятный голос, спасибо за то, что вы, в целом, есть

  • @user-proger88
    @user-proger88 2 года назад +2

    а как поставить знак не равно как в видео?

    • @lesharper8751
      @lesharper8751 2 года назад

      В видео особенный шрифт, поэтому знаки так выглядят, обычно пишут вот так !=

    • @PlatinumTechTalks
      @PlatinumTechTalks  2 года назад

      Это шрифт от JetBrains, созданный специально для разработчиков: www.jetbrains.com/ru-ru/lp/mono/

  • @vamler268
    @vamler268 3 года назад

    А есть разница между тем где создается новый Guid, в бд или в самом приложении, если да то как сделать лучше?

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад +1

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

    • @vamler268
      @vamler268 3 года назад

      @@PlatinumTechTalks Спасибо за ответ.

    • @OlegTar
      @OlegTar 2 года назад

      @@PlatinumTechTalks если в ней есть guid'ы, то скорей всего поддержку гуидов она поддерживает

  • @user-fv2bo1lf6i
    @user-fv2bo1lf6i 2 года назад

    подойдет ли данный курс для создания мессенджера (чат с разделением на беседы, возможность написать конкретному пользователю из списка контактов пользователей) по аналогии? (Клиент - WPF)

  • @this_is_denys
    @this_is_denys 2 года назад

    Как расшифровывается "opt"?

  • @alexanderspiegel6747
    @alexanderspiegel6747 3 года назад

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

    • @faelkre
      @faelkre 3 года назад +1

      Я бы рассматривал в данном случае базу данных как абстактное хранилище. CQRS вообще по хорошему реализуется так, что запись происходит в одну базу данных, а чтение из другой. Это позволяет иметь несколько баз для чтения вследствии такого масштабирования. Так вот, в вашем вопросе вы размещаете хранилище приложения и хранилище логов в одной базе данных. Т.е. это все равно queries, т.к. они не меняют данных приложения.
      Можно ли все писать в одну базу данных? Возможно что и да, зависит от вас, но я бы по карйней мере держал все в разных базах, пусть и в одном сервере базы данных.

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад +1

      @@faelkre спасибо за ответ

    • @alexanderspiegel6747
      @alexanderspiegel6747 3 года назад +1

      @@faelkre спасибо за Ваше мнение и ответ

  • @bek15071991
    @bek15071991 3 года назад +1

    Микросервисы будут?

    • @PlatinumTechTalks
      @PlatinumTechTalks  3 года назад

      нет, микросервисов не будет...

    • @asyncawait2839
      @asyncawait2839 2 года назад +4

      @@PlatinumTechTalks На, мужик, микросервисы...

  • @andreypozin8048
    @andreypozin8048 Год назад

    Библиотека MediatR не реализует паттерн Посредник.

  • @dmvlex4578
    @dmvlex4578 9 месяцев назад

    Зачем вообще прописывать отдельно маппинг , если класс реализует интерфейс IMapWith, когда мы в прошлом уроке настроили автоматическое сканирование всех классов в сборке реализующих его и создание маппинга для них с помощью ApplyMappingFromAssebly?

  • @user-re3we1xc1f
    @user-re3we1xc1f 2 года назад

    А есть ссылка на гитхаб проекта, что бы смотреть на код и слушать комментарий, а не смотреть, как молча набирают код

    • @PlatinumTechTalks
      @PlatinumTechTalks  2 года назад

      Да, в описании к каждому видео есть ссылка на код из него

  • @yakov1204
    @yakov1204 Год назад

    Делал все до этого видео, только на .Net 6 и библиотеку все выше по версии. Словил ошибку пришлось удалить все.

  • @user-fb6hs6rd8j
    @user-fb6hs6rd8j 7 месяцев назад +1

    Commands - это Update, Delete, Create. Очень похожи для всех сущностей. Можно сделать абстракцию и просто дженериком принимать тип сущности?

  • @user-vz5xw2lk1r
    @user-vz5xw2lk1r 2 года назад +1

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

  • @dr1n
    @dr1n 2 года назад

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

  • @BrownAleks
    @BrownAleks Год назад +1

    Писать код, ради того что бы писать код? Хоть какой то промежуточный результат глянуть можно?

  • @Bupyc2007
    @Bupyc2007 2 года назад +1

    using`и прописывать вручную, да вы серьезно?

    • @PlatinumTechTalks
      @PlatinumTechTalks  2 года назад +9

      Вполне серьезно в рамках такой объёмной серии видео.потому что бывает смотришь туториал и там порой не показывают откуда что импортится и это затрудняет освоение материала.поэтому было решение прописывать вручную, к тому же эти моменты ускорены и много времени просмотра не отнимают.конечно, в реальной жизни мы так не делаем:)

  • @user-vv4uq4xs8f
    @user-vv4uq4xs8f 8 месяцев назад

    Automapper 🤦🏻

  • @yava43
    @yava43 2 месяца назад +1

    мне одному кажется что это слишко?

  • @IvanenkoStepan
    @IvanenkoStepan 3 года назад

    Спасибо