Pull to refresh

Используем Entity Framework Core с приложением универсальной платформы Windows

Reading time5 min
Views11K

Вы знаете, что UWP имеет довольно особый принцип работы с данными. Это обусловлено тем, что основным способом распространения приложений является загрузка из Store. Кроме того, сама универсальность платформы подразумевает, что ОС может быть установлена на устройства различного типа. А, скажем, SQL Server на телефон пока что не устанавливают. Кроме REST сервисов единственным доступным форматом баз данных является SQLite. Радует то, что формат довольно популярный. Для работы с базами этого формата существует несколько библиотек-оберток. Ну и вот, с релизом .Net Core, под UWP становится доступной работа с Entity Framework Core. Не удержался и решил написать об этом.

Предлагаю проверить EF Core на практике и создать простенькое UWP приложение с гостевой книгой. Практического смысла в локальной базе с гостевой книгой нет, но для простого примера самое то. При желании, в реальных проектах можно синхронизировать с внешней базой.

Для начала, давайте, создадим приложение UWP или откроем уже существующее приложение. Зайдя в менеджер пакетов NuGet, вы скорее всего обнаружите, что библиотека Microsoft.NETCore.UniversalWindowsPlatform нуждается в обновлении.



Entity Framework Core работает только с версией старше, чем 5.2.2. Обновить можно нажав на кнопку Install или выполнив команду консоли менеджера пакетов NuGet

Update-Package Microsoft.NETCore.UniversalWindowsPlatform

После обновления можно установить и сам EF Core. Или поиском в менеджере пакетов NuGet по фразе Microsoft.EntityFrameworkCore.Sqlite или же командой:

Install-Package Microsoft.EntityFrameworkCore.Sqlite 

Кроме того, необходимо установить инструменты Microsoft.EntityFrameworkCore.Tools
Пока что это пререлиз, и установить инструменты можно командой консоли NuGet PM:

Install-Package Microsoft.EntityFrameworkCore.Tools –Pre

Если вы установили версию инструментов 1.0.0-preview2 (а на момент написания статьи это последняя версия), то необходимо сделать следующий fix:

Создать в корне проекта файл App.config со следующим содержанием:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.1.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Overlapped" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.1.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="4.1.0.0" newVersion="4.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Теперь можно добавить класс Model.cs с моделью данных. Для примера я создал следующую простейшую модель:

   public class MessagingContext : DbContext
   {
       public DbSet<Message> Messages { get; set; }

       protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
       {
           optionsBuilder.UseSqlite("Filename=Guestbook.db");
       }
   }

   public class Message
   {
       public int MessageId { get; set; }
       public string MessageText { get; set; }
   }

Здесь у нас класс Message для записей гостевой книги и класс MessagingContext, унаследованный от DbContext, который переопределяет метод OnConfiguring, указывая имя файла базы данных. Intellisense должен своими подчеркиваниями напомнить вам, что нужно добавить пространство имен Microsoft.EntityFrameworkCore.

Готово. Можно запустить миграцию для создания вспомогательных классов. Из консоли менеджера пакетов NuGet выполнить команду:

Add-Migration MyGuestbookMigration

где MyGuestbookMigration это произвольное наименование создаваемого класса миграции.
Об успешном выполнении вас осведомит сообщение, указывающее, что для отмены необходимо использовать команду Remove-Migration. Будет создана папка Migrations с парой классов внутри.

У меня же возникла следующая ошибка:
Add-Migration: Exception calling «CreateInstanceAndUnwrap» with «8» argument(s): «Could not load file
or assembly 'Microsoft.EntityFrameworkCore, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60' or one of its dependencies. The located assembly's manifest definition
does not match the assembly reference. (Exception from HRESULT: 0x80131040)»
At line:1 char:1
+ Add-Migration MyFirstMigration
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo: NotSpecified: (:) [Add-Migration], MethodInvocationException
+ FullyQualifiedErrorId: FileLoadException,Add-Migration

Которая заставила добавить еще пару следующих биндингов в App.config:

 <dependentAssembly>
   <assemblyIdentity name="Microsoft.EntityFrameworkCore" publicKeyToken="adb9793829ddae60" culture="neutral" />
   <bindingRedirect oldVersion="1.0.0.0" newVersion="1.0.1.0"/>
 </dependentAssembly>
 <dependentAssembly>
   <assemblyIdentity name="Microsoft.EntityFrameworkCore.Relational" publicKeyToken="adb9793829ddae60" culture="neutral" />
   <bindingRedirect oldVersion="1.0.0.0" newVersion="1.0.1.0"/>
 </dependentAssembly>

Превью, что с него возьмешь. Сейчас нам необходимо добавить код в App.xaml.cs, который будет при каждом открытии приложения применять все новые миграции к базе данных. При первом открытии приложения база данных будет создана.

Добавим 4 строчки кода в конец конструктора:

   public App()
   {
       this.InitializeComponent();
       this.Suspending += OnSuspending;

       using (var db = new MessagingContext())
       {
           db.Database.Migrate();
       }
   }

ну и кроме этого пространство имен:

using Microsoft.EntityFrameworkCore;

Созданный файл базы данных можно будет найти в каталоге LocalState.
Проще всего найти его с помощью портала устройств.

Ну или, как обычно, открыв папку приложения, которая находится, как правило, в директории C:\Users\{имя пользователя}\AppData\Local\Packages\
Для отображения записей гостевой книги добавим в MainPage.xaml элемент ListView с биндингом:

  <ListView Name="Guestbook">
       <ListView.ItemTemplate>
           <DataTemplate>
               <TextBlock Text="{Binding MessageText}" />
           </DataTemplate>
       </ListView.ItemTemplate>
   </ListView> 

В саму страницу добавим событие Loaded и обработчик:

   private void Page_Loaded(object sender, RoutedEventArgs e)
   {
       using (var db = new MessagingContext())
       {
           Guestbook.ItemsSource = db.Messages.ToList();
       }
   }

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

   <TextBox Name="txtNewPost"></TextBox>
   <Button Click="Add_Post_Click">Добавить сообщение</Button>

и

   private void Add_Post_Click(object sender, RoutedEventArgs e)
   {
       using (var db = new MessagingContext())
       {
           var post = new Message { MessageText = txtNewPost.Text };
           db.Messages.Add(post);
           db.SaveChanges();

           Guestbook.ItemsSource = db.Messages.ToList();
       }
   }

Для опытных разработчиков это все скорее новость или обзор новой доступной возможности, чем tutorial, но для тех, кто только еще начинает приведу дополнительно пример операций обновления и удаления записей:

   using (var db = new MessagingContext())
   {
       var messagesList = db.Messages.ToList<Message>();

       //Операция Update
       Message messageToUpdate = messagesList.Where(m => m.MessageId == 1).FirstOrDefault<Message>();
       messageToUpdate.MessageText = "Первое сообщение"; // изменяем текст первого сообщения

       //Операция Delete
       if (messagesList.Count >= 2)
           db.Messages.Remove(messagesList.ElementAt<Message>(1)); // удаляем вторую запись

       db.SaveChanges();
   }

» Официальный англоязычный мануал: Local SQLite on UWP
Tags:
Hubs:
Total votes 15: ↑14 and ↓1+13
Comments2

Articles