В чем смысл System.Collections.Frozen по сравнению с System.Collections.Immutable?
Immutable-коллекции являются «неизменяемыми» в том смысле, что конкретный экземпляр коллекции нельзя изменить. Однако они поощряют мутации: не изменение самого экземпляра, а создание новых экземпляров на основе исходного. Поэтому у immutable-коллекций есть методы вроде Add и Remove, которые не изменяют исходный экземпляр, а вместо этого создают новый экземпляр, содержащий это изменение (в литературе такие коллекции часто называют «персистентными коллекциями»). В результате, помимо API, ориентированного на такие операции, реализации оптимизированы под подобные сценарии, в частности — под шаринг памяти между экземплярами.
Например, если у вас есть ImmutableDictionary<string, string>, то под капотом это древовидная структура данных, и при вызове Add создаётся новый ImmutableDictionary<string, string>, который шарит максимально возможную часть исходного дерева, добавляя только необходимые узлы для нового элемента. Это означает, что хотя ImmutableDictionary и «неизменяемый», он на самом деле не оптимизирован для быстрого чтения, например, TryGetValue — это операция O(log n).
С другой стороны, новые FrozenSet<> / FrozenDictionary<> действительно неизменяемые: у них нет API, который позволял бы или поощрял добавления, удаления и т.д. Они спроектированы только под те операции, которые вы с ними выполняете — чтение. Если вам не нужны API для каких-либо мутаций, можно просто использовать FrozenSet / FrozenDictionary.
Если вы планируете использовать их долго и готовы потратить больше времени на этапе построения, чтобы привести данные к форме, которая делает их быстрее для всех последующих чтений, можно передать optimizeForReading: true в соответствующие методы, и фабрика потратит больше времени на вычисление оптимального представления, чтобы последующие операции вроде TryGetValue выполнялись очень быстро. При этом не нужно думать о хранении данных таким образом, чтобы удешевить создание производных коллекций, так как API для подобных операций просто отсутствует.
👉 @KodBlog
Immutable-коллекции являются «неизменяемыми» в том смысле, что конкретный экземпляр коллекции нельзя изменить. Однако они поощряют мутации: не изменение самого экземпляра, а создание новых экземпляров на основе исходного. Поэтому у immutable-коллекций есть методы вроде Add и Remove, которые не изменяют исходный экземпляр, а вместо этого создают новый экземпляр, содержащий это изменение (в литературе такие коллекции часто называют «персистентными коллекциями»). В результате, помимо API, ориентированного на такие операции, реализации оптимизированы под подобные сценарии, в частности — под шаринг памяти между экземплярами.
Например, если у вас есть ImmutableDictionary<string, string>, то под капотом это древовидная структура данных, и при вызове Add создаётся новый ImmutableDictionary<string, string>, который шарит максимально возможную часть исходного дерева, добавляя только необходимые узлы для нового элемента. Это означает, что хотя ImmutableDictionary и «неизменяемый», он на самом деле не оптимизирован для быстрого чтения, например, TryGetValue — это операция O(log n).
С другой стороны, новые FrozenSet<> / FrozenDictionary<> действительно неизменяемые: у них нет API, который позволял бы или поощрял добавления, удаления и т.д. Они спроектированы только под те операции, которые вы с ними выполняете — чтение. Если вам не нужны API для каких-либо мутаций, можно просто использовать FrozenSet / FrozenDictionary.
Если вы планируете использовать их долго и готовы потратить больше времени на этапе построения, чтобы привести данные к форме, которая делает их быстрее для всех последующих чтений, можно передать optimizeForReading: true в соответствующие методы, и фабрика потратит больше времени на вычисление оптимального представления, чтобы последующие операции вроде TryGetValue выполнялись очень быстро. При этом не нужно думать о хранении данных таким образом, чтобы удешевить создание производных коллекций, так как API для подобных операций просто отсутствует.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍌6👎4🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Изучайте алгоритмы — наглядно
Отличная коллекция интерактивных алгоритмов, удобно разбитых по категориям. Рекомендуется посмотреть:
https://algorithm-visualizer.org
👉 @KodBlog
Отличная коллекция интерактивных алгоритмов, удобно разбитых по категориям. Рекомендуется посмотреть:
https://algorithm-visualizer.org
Please open Telegram to view this post
VIEW IN TELEGRAM
👏4❤3
Вот хороший пример использования перехватчиков (interceptors) в EF: отслеживание того, когда ваши сущности были созданы или изменены.
Вы можете использовать ChangeTracker, чтобы проверить состояние сущности и установить соответствующие поля.
Если вы всегда используете этот DbContext в рамках HTTP-запроса, вы даже можете передавать UserId.
Вы можете использовать ChangeTracker, чтобы проверить состояние сущности и установить соответствующие поля.
Если вы всегда используете этот DbContext в рамках HTTP-запроса, вы даже можете передавать UserId.
👍4👏2
Обработка «сырого» исключения базы данных при нарушении уникального ограничения приводит к появлению некрасивого
Библиотека EntityFramework.Exceptions решает эту проблему.
https://github.com/Giorgi/EntityFramework.Exceptions
👉 @KodBlog
DbUpdateException с вложенным provider-specific исключением, которое приходится по-разному парсить для SQL Server, PostgreSQL и SQLite.Библиотека EntityFramework.Exceptions решает эту проблему.
https://github.com/Giorgi/EntityFramework.Exceptions
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - Giorgi/EntityFramework.Exceptions: Strongly typed exceptions for Entity Framework Core. Supports SQLServer, PostgreSQL…
Strongly typed exceptions for Entity Framework Core. Supports SQLServer, PostgreSQL, SQLite, Oracle and MySql. - Giorgi/EntityFramework.Exceptions
😁1
16 полезных сайтов, которые сделают тебя лучшим разработчиком:
1. roadmap.sh — дорожные карты для изучения dev-ролей
2. explainshell.com — объясняет каждый флаг в bash-командах
3. regex101.com — тестирование и отладка регулярных выражений с live-обратной связью
4. jsoncrack.com — превращает сырой JSON в визуальную диаграмму
5. bundlephobia.com — показывает размер npm-пакета до установки
6. transform.tools — мгновенно конвертирует между форматами для разработки
7. webhook.site — live URL для логирования webhook-запросов
8. devhints.io — шпаргалки по языкам и инструментам
9. httpie.io/app — браузерный HTTP-клиент для работы с API
10. caniuse.com — проверка поддержки CSS и JS в браузерах
11. squoosh.app — сжатие изображений прямо в браузере
12. carbon.now.sh — превращает код в аккуратные скриншоты
13. overapi.com — одностраничные шпаргалки по разным темам
14. shortcuts.design — горячие клавиши для популярных dev-инструментов
15. tinywow.com — бесплатный конвертер файлов
16. getfluently.app — прокачка разговорного английского с помощью AI
👉 @KodBlog
1. roadmap.sh — дорожные карты для изучения dev-ролей
2. explainshell.com — объясняет каждый флаг в bash-командах
3. regex101.com — тестирование и отладка регулярных выражений с live-обратной связью
4. jsoncrack.com — превращает сырой JSON в визуальную диаграмму
5. bundlephobia.com — показывает размер npm-пакета до установки
6. transform.tools — мгновенно конвертирует между форматами для разработки
7. webhook.site — live URL для логирования webhook-запросов
8. devhints.io — шпаргалки по языкам и инструментам
9. httpie.io/app — браузерный HTTP-клиент для работы с API
10. caniuse.com — проверка поддержки CSS и JS в браузерах
11. squoosh.app — сжатие изображений прямо в браузере
12. carbon.now.sh — превращает код в аккуратные скриншоты
13. overapi.com — одностраничные шпаргалки по разным темам
14. shortcuts.design — горячие клавиши для популярных dev-инструментов
15. tinywow.com — бесплатный конвертер файлов
16. getfluently.app — прокачка разговорного английского с помощью AI
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤3👍3🍌1
CA1507: Используйте
У кого включено это правило анализа кода?
👉 @KodBlog
nameof вместо строкового литералаУ кого включено это правило анализа кода?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16👏1🍌1
Инжект настроек в .NET
У тебя есть 3 основных интерфейса на выбор. Но если выбрать не тот — приложение может просто игнорировать изменения конфигурации.
Вот простое объяснение:
1️⃣ IOptions
• Считывается один раз при старте приложения
• Кэшируется на весь жизненный цикл
• Подходит для статичных настроек, которые не меняются
2️⃣ IOptionsSnapshot
• Пересчитывается на каждый запрос
• Подхватывает изменения в
• Идеален для web API (Scoped lifetime)
3️⃣ IOptionsMonitor
• Обновляется в реальном времени
• Триггерит событие при изменении настроек
• Подходит для фоновых сервисов (Singleton lifetime)
Правило большого пальца (Rule of Thumb):
Используй
Переходи на
Используй
👉 @KodBlog
У тебя есть 3 основных интерфейса на выбор. Но если выбрать не тот — приложение может просто игнорировать изменения конфигурации.
Вот простое объяснение:
• Считывается один раз при старте приложения
• Кэшируется на весь жизненный цикл
• Подходит для статичных настроек, которые не меняются
• Пересчитывается на каждый запрос
• Подхватывает изменения в
appsettings.json без перезапуска• Идеален для web API (Scoped lifetime)
• Обновляется в реальном времени
• Триггерит событие при изменении настроек
• Подходит для фоновых сервисов (Singleton lifetime)
Правило большого пальца (Rule of Thumb):
Используй
IOptions для статической конфигурации.Переходи на
IOptionsSnapshot в веб-приложениях.Используй
IOptionsMonitor, когда нужны уведомления об изменениях в background-задачах.Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🍌2
Мой любимый способ конфигурировать Serilog — через настройки приложения.
Можно настраивать уровни логирования, внешние sinks, enrichers и многое другое.
Это также значит, что конфигурацию Serilog можно менять без изменений в коде.
👉 @KodBlog
Можно настраивать уровни логирования, внешние sinks, enrichers и многое другое.
Это также значит, что конфигурацию Serilog можно менять без изменений в коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👏1
Большинство .NET-разработчиков реализуют кэширование сложным способом.
Они пишут шаблонный (boilerplate) код в каждом методе сервиса — проверяют кэш, делают запрос к базе, сохраняют результат, обрабатывают время жизни.
Есть способ лучше, который почти не требует изменений в коде.
Он называется
И работает он совершенно иначе, чем
Ключевое отличие:
-
-
При наличии кэша не вызываются ни обработчик endpoint’а, ни запрос к базе, ни бизнес-логика.
Что делает
- Добавление кэширования одним атрибутом — без boilerplate-кода в сервисах
- Встроенный cache lock предотвращает проблему «thundering herd»
- Именованные политики задают поведение кэша централизованно
- Инвалидация по тегам позволяет сбрасывать группы связанных записей одним вызовом
- Опции
Но вот где большинство разработчиков ошибается:
Кэшируют ответы авторизованных API без разделения по пользователям
→ Данные пользователя A могут быть отданы пользователю B
→ Это реальная уязвимость безопасности
Читать гайд
👉 @KodBlog
Они пишут шаблонный (boilerplate) код в каждом методе сервиса — проверяют кэш, делают запрос к базе, сохраняют результат, обрабатывают время жизни.
Есть способ лучше, который почти не требует изменений в коде.
Он называется
Output Cache middleware в ASP.NET Core.И работает он совершенно иначе, чем
IMemoryCache или IDistributedCache.Ключевое отличие:
-
IMemoryCache и IDistributedCache кэшируют объекты внутри кода приложения-
Output Cache перехватывает HTTP-ответ на уровне middleware, сохраняет его целиком и отдает повторноПри наличии кэша не вызываются ни обработчик endpoint’а, ни запрос к базе, ни бизнес-логика.
Что делает
Output Cache мощным:- Добавление кэширования одним атрибутом — без boilerplate-кода в сервисах
- Встроенный cache lock предотвращает проблему «thundering herd»
- Именованные политики задают поведение кэша централизованно
- Инвалидация по тегам позволяет сбрасывать группы связанных записей одним вызовом
- Опции
VaryBy позволяют кэшировать отдельные ответы по заголовкам, query string, route-параметрам или кастомной логикеНо вот где большинство разработчиков ошибается:
Кэшируют ответы авторизованных API без разделения по пользователям
→ Данные пользователя A могут быть отданы пользователю B
→ Это реальная уязвимость безопасности
Читать гайд
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8😁2
Ищешь альтернативу Postman?
Apidog — это all-in-one инструмент для работы с API.
✓ Проектируй и управляй спецификациями API
✓ Мокай и тестируй endpoints в одном месте
✓ Генерируй документацию автоматически
✓ Тестируй интеграции с ИИ, такие как ChatGPT
Доступен в веб-версии и приложении с бесплатным тарифом:
→ http://midu.link/apidog
👉 @KodBlog
Apidog — это all-in-one инструмент для работы с API.
✓ Проектируй и управляй спецификациями API
✓ Мокай и тестируй endpoints в одном месте
✓ Генерируй документацию автоматически
✓ Тестируй интеграции с ИИ, такие как ChatGPT
Доступен в веб-версии и приложении с бесплатным тарифом:
→ http://midu.link/apidog
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4😁4
Что такое breaking change для API?
Вот несколько примеров:
- Удаление или переименование API или параметров API
- Изменение поведения существующих API
- Изменение кодов ошибок API
Breaking change означает, что вам нужно версионировать API — иначе вы рискуете сломать существующих клиентов.
👉 @KodBlog
Вот несколько примеров:
- Удаление или переименование API или параметров API
- Изменение поведения существующих API
- Изменение кодов ошибок API
Breaking change означает, что вам нужно версионировать API — иначе вы рискуете сломать существующих клиентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6😁1
Отличные ресурсы по системному дизайну
http://github.com/ashishps1/awesome-system-design-resources
Что внутри:
1. Базовые концепции — теорема CAP, консистентное хеширование, масштабируемость, доступность
2. Основы сетей — DNS, балансировка нагрузки, модель OSI, WebSockets
3. Глубокое погружение в базы данных — шардирование, репликация, SQL vs NoSQL
4. Разборы реальных систем — Twitter, Netflix, Uber, Google Drive
5. Включены диаграммы и примеры реализации кода
👉 @KodBlog
http://github.com/ashishps1/awesome-system-design-resources
Что внутри:
1. Базовые концепции — теорема CAP, консистентное хеширование, масштабируемость, доступность
2. Основы сетей — DNS, балансировка нагрузки, модель OSI, WebSockets
3. Глубокое погружение в базы данных — шардирование, репликация, SQL vs NoSQL
4. Разборы реальных систем — Twitter, Netflix, Uber, Google Drive
5. Включены диаграммы и примеры реализации кода
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍌2
Большинство .NET-разработчиков используют
Но очень немногие делают его поведением по умолчанию — и тем самым теряют реальную производительность.
Вот полная картина query tracking в EF Core, которую редко объясняют в одном месте.
Три метода. Одна цель: не трекать то, что вы не собираетесь менять.
AsNoTracking()
Самый быстрый вариант. Полностью обходит change tracker.
Идеален для любых read-only запросов — списки, результаты поиска, отчёты, фоновые задачи.
Есть один нюанс: если одна и та же сущность появляется через разные join’ы, EF Core создаст два разных C#-объекта в памяти вместо одного.
Это может незаметно ломать поведение.
AsNoTrackingWithIdentityResolution()
Даёт тот же плюс отсутствия трекинга, но решает проблему дубликатов объектов.
EF Core по-прежнему не использует change tracker, но поддерживает identity map, благодаря чему одна и та же сущность всегда соответствует одному и тому же C#-объекту.
Немного медленнее, чем чистый
UseQueryTrackingBehavior()
Перестаньте писать
Задайте это глобально в
Теперь все запросы по умолчанию — без трекинга.
А там, где нужно изменение данных, явно используйте
Используйте NoTracking, когда:
→ read-only API endpoint’ы
→ пагинация и списки
→ отчёты и экспорт данных
→ чтение данных в фоновых задачах
→ страницы с результатами поиска
Оставляйте tracking, когда:
→ загружаете сущность для последующего обновления
→ после запроса вызывается
→ мутируете сложные графы объектов
→ работаете с disconnected-сценариями сущностей
👉 @KodBlog
AsNoTracking() время от времени — когда вспоминают.Но очень немногие делают его поведением по умолчанию — и тем самым теряют реальную производительность.
Вот полная картина query tracking в EF Core, которую редко объясняют в одном месте.
Три метода. Одна цель: не трекать то, что вы не собираетесь менять.
AsNoTracking()
Самый быстрый вариант. Полностью обходит change tracker.
Идеален для любых read-only запросов — списки, результаты поиска, отчёты, фоновые задачи.
Есть один нюанс: если одна и та же сущность появляется через разные join’ы, EF Core создаст два разных C#-объекта в памяти вместо одного.
Это может незаметно ломать поведение.
AsNoTrackingWithIdentityResolution()
Даёт тот же плюс отсутствия трекинга, но решает проблему дубликатов объектов.
EF Core по-прежнему не использует change tracker, но поддерживает identity map, благодаря чему одна и та же сущность всегда соответствует одному и тому же C#-объекту.
Немного медленнее, чем чистый
AsNoTracking, но правильный выбор для сложных запросов с Include.UseQueryTrackingBehavior()
Перестаньте писать
AsNoTracking в каждом запросе.Задайте это глобально в
DbContext при старте приложения.Теперь все запросы по умолчанию — без трекинга.
А там, где нужно изменение данных, явно используйте
AsTracking().Используйте NoTracking, когда:
→ read-only API endpoint’ы
→ пагинация и списки
→ отчёты и экспорт данных
→ чтение данных в фоновых задачах
→ страницы с результатами поиска
Оставляйте tracking, когда:
→ загружаете сущность для последующего обновления
→ после запроса вызывается
SaveChanges→ мутируете сложные графы объектов
→ работаете с disconnected-сценариями сущностей
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🔥3😁1
DelegatingHandlers позволяют добавлять поведение до или после выполнения запросов через HttpClient.
Это как middleware, но для исходящих (outgoing) запросов.
Отличный кейс использования этой возможности?
Добавление заголовков аутентификации к запросу.👇
👉 @KodBlog
Это как middleware, но для исходящих (outgoing) запросов.
Отличный кейс использования этой возможности?
Добавление заголовков аутентификации к запросу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👀2
Однажды я заплатил $40 за .NET-приложение с самописным ORM.
В нём были SQL-инъекции, сломанные транзакции и ноль тестов.
Вот 6 ORM-репозиториев, которые действительно стоят внимания:
1. Entity Framework Core - https://github.com/dotnet/efcore
2. Dapper - https://github.com/DapperLib/Dapper
3. NHibernate - https://github.com/nhibernate/nhibernate-core
4. linq2db - https://github.com/linq2db/linq2db
5. Marten - https://github.com/JasperFx/marten
6. SqlKata - https://github.com/sqlkata/querybuilder
👉 @KodBlog
В нём были SQL-инъекции, сломанные транзакции и ноль тестов.
Вот 6 ORM-репозиториев, которые действительно стоят внимания:
1. Entity Framework Core - https://github.com/dotnet/efcore
2. Dapper - https://github.com/DapperLib/Dapper
3. NHibernate - https://github.com/nhibernate/nhibernate-core
4. linq2db - https://github.com/linq2db/linq2db
5. Marten - https://github.com/JasperFx/marten
6. SqlKata - https://github.com/sqlkata/querybuilder
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4😁2👍1
Этот динамический парсинг JSON уже не раз меня подводил — я обычно кастую к
В JSON.NET (
Не первый раз на это натыкаюсь, и, скорее всего, не последний😂
👉 @KodBlog
string через as string, где это возможно.В JSON.NET (
JObject / JValue) значения ведут себя как dynamic при цепочках обращений, но при этом не кастуются, потому что по сути это Expando-подобные объекты.Не первый раз на это натыкаюсь, и, скорее всего, не последний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤩1🍾1
Модули в модульном монолите могут взаимодействовать только через свой публичный API.
Но как это обеспечить на уровне архитектуры?
С помощью тестирования архитектуры.
Вот пример кода с тестом, который проверяет направление зависимостей между модулями.
👉 @KodBlog
Но как это обеспечить на уровне архитектуры?
С помощью тестирования архитектуры.
Вот пример кода с тестом, который проверяет направление зависимостей между модулями.
[Fact]
public void TicketingModule_ShouldNotHaveDependencyOn_AnyOtherModule()
{
string[] otherModules = [
UsersNamespace,
EventsNamespace,
AttendanceNamespace
];
string[] integrationEventsModules = [
UsersIntegrationEventsNamespace,
EventsIntegrationEventsNamespace,
AttendanceIntegrationEventsNamespace
];
List<Assembly> ticketingAssemblies =
[
typeof(Order).Assembly,
Modules.Ticketing.Application.AssemblyReference.Assembly,
Modules.Ticketing.Presentation.AssemblyReference.Assembly,
typeof(TicketingModule).Assembly
];
Types.InAssemblies(ticketingAssemblies)
.That()
.DoNotHaveDependencyOnAny(integrationEventsModules)
.Should()
.NotHaveDependencyOnAny(otherModules)
.GetResult()
.ShouldBeSuccessful();
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🍾1
Кто-то собрал все задачи с LeetCode, сгруппированные по компаниям, и выложил это в публичный репозиторий на GitHub. Более 300 компаний: Google, Meta, Amazon, Jane Street, Citadel, Stripe, Snowflake — практически каждый крупный работодатель в техе, у каждого своя папка.
Внутри папок всё отсортировано по тому, насколько недавно задача встречалась — за последние 30 дней, 60 дней, 90 дней и за всё время.
Это означает, что если у тебя интервью в Google в пятницу, ты можешь открыть папку Google и увидеть, какие задачи они задавали в этом месяце.
Не самая приятная правда, которая здесь вскрывается: компании месяцами переиспользуют одни и те же задачи. Интервью — это не непредсказуемое испытание, а набор паттернов. А паттерны можно изучать.
Большинство кандидатов решают 500 случайных задач на LeetCode и надеются на лучшее. Те, кто знают про этот репозиторий, тратят то же время на 30 задач, которые их целевая компания задавала за последние 30 дней.
Те же усилия. Совершенно другие шансы.
Технические интервью больше вознаграждают подготовку, чем способности — сильнее, чем кто-либо в найме готов это признать. Этот репозиторий просто делает это очевидным.
Лично я этим не пользовался, делюсь на случай, если кому-то пригодится.
P.S. Мы всё ещё решаем LeetCode в 2026?
👉 @KodBlog
Внутри папок всё отсортировано по тому, насколько недавно задача встречалась — за последние 30 дней, 60 дней, 90 дней и за всё время.
Это означает, что если у тебя интервью в Google в пятницу, ты можешь открыть папку Google и увидеть, какие задачи они задавали в этом месяце.
Не самая приятная правда, которая здесь вскрывается: компании месяцами переиспользуют одни и те же задачи. Интервью — это не непредсказуемое испытание, а набор паттернов. А паттерны можно изучать.
Большинство кандидатов решают 500 случайных задач на LeetCode и надеются на лучшее. Те, кто знают про этот репозиторий, тратят то же время на 30 задач, которые их целевая компания задавала за последние 30 дней.
Те же усилия. Совершенно другие шансы.
Технические интервью больше вознаграждают подготовку, чем способности — сильнее, чем кто-либо в найме готов это признать. Этот репозиторий просто делает это очевидным.
Лично я этим не пользовался, делюсь на случай, если кому-то пригодится.
P.S. Мы всё ещё решаем LeetCode в 2026?
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3🤔1
Пользовательские SQL-запросы в миграциях EF? Это возможно.
Пользовательские SQL-команды полезны, когда мы не можем выразить что-то через Fluent API EF.
Я использовал их для переноса данных из одного столбца в другой или для создания сложных индексов.
- Создайте пустую миграцию
- Напишите свои SQL-запросы
👉 @KodBlog
Пользовательские SQL-команды полезны, когда мы не можем выразить что-то через Fluent API EF.
Я использовал их для переноса данных из одного столбца в другой или для создания сложных индексов.
- Создайте пустую миграцию
- Напишите свои SQL-запросы
public partial class Update_Products : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("<YOUR CUSTOM SQL HERE>");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// You are also responsible for reverting any changes.
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👏3👍2
Младший разработчик использует EF Core напрямую в контроллере.
Средний разработчик использует BaseRepository, IUnitOfWork, IOrderRepository, IOrderDataAccess, IOrderQueryBuilder.
Старший разработчик использует EF Core без репозитория.
Когда ваше приложение маленькое, использование паттерна Репозиторий кажется простым.
То, что начинается как простая операция CRUD с 4 методами, быстро превращается в большой класс с запросами для чтения и записи в базу данных для всех возможных случаев.
По мере роста вашего домена вы сталкиваетесь со следующими проблемами:
- Вы создаете репозиторий для каждой новой сущности
- Куда относятся методы, работающие с несколькими сущностями?
- Вы создаете репозитории с 10-20 методами
Я часто слышу следующие распространенные оправдания для использования репозиториев:
𝟭. "Мы можем позже сменить базу данных."
В 99% случаев вам не нужно будет менять базу данных.
- Переход от одной SQL базы данных к другой? EF Core справится с этим.
- Использование хранимых процедур, триггеров? Тогда их нужно переписать на уровне базы данных.
- Переход от реляционной базы данных к документной? Вам нужно будет изменить модель данных, запросы и шаблоны доступа. Вы не сможете просто заменить реализации репозиториев.
𝟮. "Это облегчает тестирование."
Некоторые утверждают, что мокирование репозитория проще, чем мокирование DbContext.
Но это скрывает большую проблему: вы тестируете абстракцию абстракции.
Мокирование репозиториев часто приводит к хрупким тестам, которые не отражают реальное поведение запросов.
Вместо этого лучше использовать реальный EF Core с базой данных в памяти или, что еще лучше, писать интеграционные тесты.
𝟯. "Это обеспечивает разделение ответственностей."
Репозитории часто используются для того, чтобы держать бизнес-слой отдельно от EF Core. Но на практике это разделение создает больше путаницы, чем ясности.
По мере того как ваши фичи растут, вам приходится:
- Внедрять несколько репозиториев в ваши сервисы
- Или переносить логику, работающую с несколькими сущностями, в жирный репозиторий
Вместо чистого разделения вы получаете больше косвенных ссылок, больше шаблонного кода и трудный для понимания код.
DbContext в EF Core уже реализует паттерны Репозиторий и Unit of Work, как указано в официальном описании кода DbContext.
Я использую EF Core напрямую в кейсах использования и сервисах моего приложения. Это прагматичный подход, который приносит мне больше преимуществ, чем недостатков.
👉 @KodBlog
Средний разработчик использует BaseRepository, IUnitOfWork, IOrderRepository, IOrderDataAccess, IOrderQueryBuilder.
Старший разработчик использует EF Core без репозитория.
Когда ваше приложение маленькое, использование паттерна Репозиторий кажется простым.
То, что начинается как простая операция CRUD с 4 методами, быстро превращается в большой класс с запросами для чтения и записи в базу данных для всех возможных случаев.
По мере роста вашего домена вы сталкиваетесь со следующими проблемами:
- Вы создаете репозиторий для каждой новой сущности
- Куда относятся методы, работающие с несколькими сущностями?
- Вы создаете репозитории с 10-20 методами
Я часто слышу следующие распространенные оправдания для использования репозиториев:
𝟭. "Мы можем позже сменить базу данных."
В 99% случаев вам не нужно будет менять базу данных.
- Переход от одной SQL базы данных к другой? EF Core справится с этим.
- Использование хранимых процедур, триггеров? Тогда их нужно переписать на уровне базы данных.
- Переход от реляционной базы данных к документной? Вам нужно будет изменить модель данных, запросы и шаблоны доступа. Вы не сможете просто заменить реализации репозиториев.
𝟮. "Это облегчает тестирование."
Некоторые утверждают, что мокирование репозитория проще, чем мокирование DbContext.
Но это скрывает большую проблему: вы тестируете абстракцию абстракции.
Мокирование репозиториев часто приводит к хрупким тестам, которые не отражают реальное поведение запросов.
Вместо этого лучше использовать реальный EF Core с базой данных в памяти или, что еще лучше, писать интеграционные тесты.
𝟯. "Это обеспечивает разделение ответственностей."
Репозитории часто используются для того, чтобы держать бизнес-слой отдельно от EF Core. Но на практике это разделение создает больше путаницы, чем ясности.
По мере того как ваши фичи растут, вам приходится:
- Внедрять несколько репозиториев в ваши сервисы
- Или переносить логику, работающую с несколькими сущностями, в жирный репозиторий
Вместо чистого разделения вы получаете больше косвенных ссылок, больше шаблонного кода и трудный для понимания код.
DbContext в EF Core уже реализует паттерны Репозиторий и Unit of Work, как указано в официальном описании кода DbContext.
Я использую EF Core напрямую в кейсах использования и сервисах моего приложения. Это прагматичный подход, который приносит мне больше преимуществ, чем недостатков.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11💯6👎2❤1👏1