Entity Framework c Code-First миграциями для .Net Maui
Если вы, как и я, уже являетесь большим поклонником Microsoft Entity Framework и хотели бы начать использовать его локально в своем мобильном приложении, с появлением .Net Maui на рынке, это стало возможным.
Небольшое замечание: для ускорения времени запуска мобильного приложения может быть лучше хранить данные, используемые во время загрузки, в локальном хранилище мобильного устройства в форме json. Но, когда дело дойдет до работы с большими локальными данными, использования фильтров, сортировки и т. д., EF определенно подойдет идеально.
Цель этой статьи — помочь избежать хлопот, связанных с поиском различных решений небольших проблем при реализации production-ready мобильной локальной базы данных и создании для нее миграций на компьютерах Windows и Mac. Исходный код примера приложения доступен по ссылке, указанной в конце. Как вы сможете увидеть, это будет типовой шаблон приложения Maui с добавленной логикой базы данных EF.
Проверенным стандартом базы данных мобильного клиента является SQLite. Ну что ж, отправимся за пакетом nuget Microsoft.EntityFrameworkCore.Sqlite, также установим SQLitePCLRaw.bundle_e_sqlite3 для нативной поддержки sqlite. Для создания миграций EF нам также потребуется установить Microsoft.EntityFrameworkCore.Tools.
Для тех, кто не уверен, для чего нужны миграции, в основном, это код, который инструктирует EF о структуре базы данных для создания и использования. Важным преимуществом здесь является то, что когда вы меняете свои модели, вам лишь нужно будет сгенерировать утилитой дополнительные миграции для EF, чтобы автоматически изменить соответствующим образом существующую базу данных, добавляя-удаляя таблицы, столбцы и т. д.
Теперь, нюанс в том, что мы не можем установить эти нагеты в наш проект maui, потому что, как только мы попытаемся создать миграцию, то получим ошибку:
Startup project 'MauiEF.Client' targets platform 'Android'. The Entity Framework Core Package Manager Console Tools don't support this platform. See https://aka.ms/efcore-docs-pmc-tfms for more information.
… поэтому нужно будет найти способ это обойти. Поскольку мы уже знаем, что инструменты проектирования EF имеют неподдерживаемые платформы, нам нужно будет создать специальный проект «Мигратор», который будет напрямую запускаться EF и будет таргетить чистый .net 7.0, тогда сможем создавать миграции на своем компьютере, Windows или Mac.
И проект «Мигратор», и наш проект-клиент должны будут иметь доступ к базе данных, поэтому мы переместим весь наш код, связанный с ней, в отдельный общий проект. Тогда структура решения будет выглядеть так:
Проект Shared будет иметь следующие зависимости
проект Migrator, для создания миграций, дополнительно потребует:
Теперь перейдем к созданию модели БД. Определим ее в проекте Shared следующим образом:
Обратите внимание на два конструктора: один для средства миграции EF, второй — для нашего приложения. Database.Migrate();
создает базу данных, если она еще не существует, и/или применяет последние миграции.
Возможно, вы захотите также перед этим использовать метод Database.EnsureDeleted();
для того, чтобы стереть всю базу данных при запуске, иногда полезно в режиме отладки.
Если у вас появится критическое обновление приложения, вы также можете просто изменить имя файла базы данных, чтобы воссоздать базу данных с нуля для существующих пользователей.
Итак, теперь мы можем добавить зависимость для нашего контекста в MauiProgram.cs:
builder.Services.AddTransient
Исходный код примера специально не включает миграции. Если вы просто скомпилируете и запустите решение, оно вызовет исключение, так как EF не будет знать, как вы хотите, чтобы она выполнила Migrate();
.
Однако, миграцию очень легко создать.
Если вы используете Visual Studio для Windows:
Измените стартовый проект с Client на Migrator.
Откройте Консоль диспетчера пакетов: View->Other Windows->Package Manager Console
. У меня нет VS на русском языке, подозреваю, что там это будет называться Вид->Другие окна->Консоль диспетчера пакетов
.
Установите проект по умолчанию (default project) как Shared, EF будет искать модель контекста внутри и добавит в этот проект миграции.
Введите следующую команду, чтобы создать начальную миграцию:
add-migration Initial -Context MauiEF.Shared.Services.LocalDatabase -Verbose
Следующий метод, использующий командной строку, используем в Visual Studio для Mac.
1 Откройте консоль: щелкните правой кнопкой мыши имя своего решения и выберите «Открыть в терминале». Вы должны попасть в папку решения.
2 Введите следующую команду, чтобы создать начальную миграцию через командную строку:
dotnet ef migrations add Initial -s Migrator -p Shared -c MauiEF.Shared.Services.LocalDatabase
Тут мы указали подпапку стартового проекта через -s Migrator и подпапку проекта по умолчанию через -p Shared.
Если вы столкнулись с ошибкой из-за отсутствия команды ef, установите ее и добавьте в глобальный путь:
dotnet tool install --global dotnet-ef export PATH="$PATH:/Users/YOUR_USERNAME/.dotnet/tools"
Каждый раз, когда вы поменяете модели контекста, вам придется создавать дополнительные миграции. Таким образом, ваше уже опубликованное приложение не сломается, если вы выпустите новую версию с измененными миграциями, EF (скорее всего) сохранит существующую базу данных пользователя и изменит ее в соответствии с новой схемой при инициализации вашей модели контекста. Почему «скорее всего»? Поскольку вы можете изменить свои модели таким образом, что связь или свойство внешнего ключа будут потеряны, но в этом случае EF предупредит вас при создании миграции с чем-то вроде «Warning data will be lost», так что управление данными в старых версиях приложения находится под вашим контролем.
Чтобы создать новую миграцию, просто создайте для нее уникальное имя (пример для Visual Studio для Windows):
add-migration Change1 -Context MauiEF.Shared.Services.LocalDatabase -Verbose
Теперь мы можем скомпилировать наше приложение и запустить его, созданные пользователем данные будут сохраняться локально на мобильном устройстве. Операции для работы с базой данных мы будем запускать асинхронно, не блокируя поток пользовательского интерфейса.
Напоследок, небольшое примечание: когда вы скомпилируете ваше приложение EF Maui под iOS в Release-конфигурации, оно может вылететь на реальном устройстве, из-за того, что iOS AOT компиляция не поддерживает некоторые методы EF. Я бы не хотел быть здесь вдаваться в детали, вы можете прочитать об этом подробнее, но решение состоит в том, чтобы добавить немного специй в файл проекта клиента для этого конкретного случая:
Приложения, скомпилированные с такими настройками, уже были опубликованы в AppStore, влияние на производительность не ощущается.
Надеюсь, эта небольшая статья окажется для вас полезной!
Исходный код примера с вариантом этой статьи на английском языке доступен на гитхаб.