Введение в Entity Framework
В течение достаточно долгого времени Entity Framework был одним из моих любимых проектов. Для тех, кто еще этого не знает, скажем, что Entity Framework недавно обновился с версии 6.X до переписанной 7.X (Core). При этом главной целью было сохранение легкого и очень расширяемого ORM.
И вот что постоянно было для меня сложностью:
Мне хотелось использовать Entity Framework в своих проектах Xamarin.
Но на протяжении последних трех лет такой возможности просто не было. По правде говоря, я предпринял попытку добиться своего несколько лет тому назад, но затем бросил эту затею, так как проходящего инструмента на тот момент просто не существовало. Короче говоря, мысль о том, чтобы заставить это работать, стала для меня идей фикс.
Инструменты
Итак, давайте рассмотрим инструменты, которые нам понадобятся для того, чтобы сделать наш план осуществимым. Давайте изучим этот вопрос, посмотрев на него с высоты:
- SQLite Provider — нам понадобится место для хранения наших данных. Учитывая тот факт, что SQLite является идеальным решением для мобильных устройств, мы воспользуемся пакетом SQLite Entity Framework:
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/
- Entity Framework Core — нам понадобится ORM для управления операциями CRUD и миграции базы данных:
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/
Отлично! Теперь мы готовы выйти на старт.
Приступаем
Создание библиотеки NetStandard
Итак, первое, что мы сделаем — это создадим библиотеку netstandard. Для этого создайте проект PCL:
Поскольку библиотеки netstandard на данный момент у нас еще нет, давайте конвертируем ее, перейдя в свойства проекта
После того как данный набор будет получен, нам нужно удостовериться в том, что у нас имеется требуемый минимум для двух пакетов NuGet, с которыми мы связались выше:
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/
Судя по всему, зависимость здесь — netstandard 1.3. Следовательно, давайте удостоверимся в том, что наш проект netstandard ориентирован на эту версию:
Создание проекта Xamarin.Android
Здесь от нас не требуется ничего особенного, нужно просто создать проект, следуя по пути File -> New Single-View App (Android) Project:
Добавление пакетов NuGet
Этот шаг, как правило, проще всего сделать на уровне проекта, нежели решения, поскольку NuGet в некоторых случаях не слишком-то дружит с различными структурами проекта (.csproj по сравнению с project.json)
Добавление пакетов NuGet к библиотеке netstandard
Добавление пакетов NuGet к проекту Xamarin.Android
Определение DbContext
Если Вы уже использовали Entity Framework, то должны быть очень хорошо знакомы с тем, как мы определяем DbContext и также наши основополагающие модели, которые, в свою очередь, определяют схему базы данных.
Так что давайте начнем с простой модели данных, которую назовем Cat.cs:
1 2 3 4 5 6 7 | public class Cat { [Key] public int CatId { get; set; } public string Name { get; set; } public int MeowsPerSecond { get; set; } } |
Теперь следует удостовериться в том, что она отделена от нашего DbContext, и мы это сделаем путем определения нового контекста, который назовем CatContext.cs. Вы могли заметить, что у нас имеется строка DatabasePath. Мы используем ее позднее, когда нам нужно будет сообщить Entity Framework, где хранить нашу базу данных на диске:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class CatContext : DbContext { public DbSet<Cat> Cats { get; set; } private string DatabasePath { get; set; } public CatContext() { } public CatContext(string databasePath) { DatabasePath = databasePath; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite($"Filename={DatabasePath}"); } } |
Реализация контекста
Сперва мы должны убедиться в том, что наш проект Xamarin.Android ссылается на библиотеку netstandard.
После того как мы это сделаем, можно уже будет реализовать наш MainActivity.cs с определенным кодом Entity Framework!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | [Activity(Label = "EntityFrameworkWithXamarin.Droid", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { int count = 1; protected async override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it Button button = FindViewById<Button>(Resource.Id.MyButton); button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); }; TextView textView = FindViewById<TextView>(Resource.Id.TextView1); var dbFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); var fileName = "Cats.db"; var dbFullPath = Path.Combine(dbFolder, fileName); try { using (var db = new CatContext(dbFullPath)) { await db.Database.MigrateAsync(); //We need to ensure the latest Migration was added. This is different than EnsureDatabaseCreated. Cat catGary = new Cat() { CatId = 1, Name = "Gary", MeowsPerSecond = 5 }; Cat catJack = new Cat() { CatId = 2, Name = "Jack", MeowsPerSecond = 11 }; Cat catLuna = new Cat() { CatId = 3, Name = "Luna", MeowsPerSecond = 3 }; List<Cat> catsInTheHat = new List<Cat>() { catGary, catJack, catLuna }; if(await db.Cats.CountAsync() < 3) { await db.Cats.AddRangeAsync(catsInTheHat); await db.SaveChangesAsync(); } var catsInTheBag = await db.Cats.ToListAsync(); foreach(var cat in catsInTheBag) { textView.Text += $"{cat.CatId} - {cat.Name} - {cat.MeowsPerSecond}" + System.Environment.NewLine; } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } } |
Давайте попробуем запустить этот код.
1 | Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: Cats'. |
Похоже, мы упустили основную функцию Entity Framework, которой являются миграции, предназначенные для создания нашей схемы базы данных.
Что за ерунда… так дело не пойдет. У нас нет подходящего способа для создания миграций Entity Framework изнутри проекта Xamarin.Android или библиотеки netstandard. Давайте используем обходной путь, создав новое консольное приложение netcore, с тем чтобы мы смогли генерировать миграции.
Мы должны добавить в этот проект Entity Framework Tools, Entity Framework Core Design и Entity Framework Core, с тем чтобы у нас появилась возможность использовать командную строку для создания миграций.
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools.DotNet
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Design/
Теперь мы должны перейти к нашим Cat.cs и CatContext.cs, дабы удостовериться в том, что там есть DbContext, для которого могут генерироваться миграции. Сейчас консольное приложение должно выглядеть следующим образом:
Теперь мы можем генерировать схему для нашего контекста. И для того чтобы это сделать, давайте воспользуемся новым инструментом dotnet. Откройте новую консоль в текущем хранилище Console App:
Теперь нам нужно сгенерировать начальную миграцию.
1 | dotnet ef migrations add Initial |
Вот так должна генерироваться миграция:
Сейчас мы должны взять начальные миграции, сгенерированные в папке Migrations нашего проекта, и просто переместить их в библиотеку netstandard.
Заметьте: Вы можете просто заменить пространство имен этих двух сгенерированных файлов на название вашего пространства имен у библиотеки netstandard.
Давайте вновь запустим наш проект Xamarin.Android, чтобы посмотреть, не столкнемся ли мы с какими-либо другими исключениями:
Ну что ж, похоже, все на этот раз работает как надо! Наш план по добавлению моделей Cat и получению их удался!
Если хочется более внимательно взглянуть на сгенерированный файл SQLite, тогда следует воспользоваться эмулятором и открыть ADM (монитор устройств Android):
Заглянув в папку, расположенную по пути data/data/files, мы найдем там Cats.db, который мы создали.
Теперь вы можете взять этот файл и открыть его в любом просмотрщике SQLite.
Примечание: Я использую DB Browser для SQLite (https://sqlitebrowser.org/)
Заключение
Исходный код: https://github.com/JonDouglas/EntityFrameworkWithXamarin
На то, чтобы справиться с Entity Framework потребовалось аж три года. Там не менее я должен выразить свою благодарность всем, кто привел Entity Framework к тому состоянию, в котором последний сейчас прибывает. Мне очень нравится следить за развитием этого проекта.
Автор: Jon Douglas
Источник: Статья в блоге автора
Написать ответ