Глава 7. Connector/NET для Entity Framework

Entity Framework это имя, данное ряду технологий, которые поддерживают разработку ориентированных на данные приложений. MySQL Connector/NET поддерживает Entity Framework 6.0 (EF6 или EF 6.4) и Entity Framework Core (EF Core), который является новой структурой, доступной разработчикам .NET, которые работают с данными MySQL, используя объекты .NET.

Следующая таблица показывает набор версий Connector/NET и возможности Entity Framework.

Таблица 7.1. Версии Connector/NET и поддержка Entity Framework

Версия Connector/NET EF6 | EF 6.4EF Core
8.0
  • EF 6.4: Полная кросс-платформенная поддержка в 8.0.22 и выше.

  • EF6: Полная поддержка только в Windows 8.0.11 и выше.

  • EF Core 3.1.1: Полная поддержка в 8.0.20 и выше. (Connector/NET 8.0.20 не поддерживает EF Core 2.0 или 2.1).

  • EF Core 2.1: Полная поддержка в 8.0.13 и выше.

  • EF Core 2.0: Частичная поддержка в 8.0.8 до 8.0.12 (Без scaffolding).

6.10
  • EF6: Полная поддержка в Windows.

  • EF Core 2.0: Полная поддержка в 6.10.8 и выше. Частичная поддержка в 6.10.5 до 6.10.7 (Без scaffolding).

7.1. Поддержка Entity Framework 6

MySQL Connector/NET объединяет поддержку Entity Framework 6 (EF6), которая теперь включает поддержку развертывания кросс-платформенного приложения с версией EF 6.4. В этой главе описывается, как формировать и использовать функции EF6, которые осуществляются в Connector/NET.

Минимальные требования для EF6 только в Windows

Минимальные требования для EF 6.4 с поддержкой Cross-Platform

Конфигурация

У версий MySQL Connector/NET 8.0 есть схема именования для EF6 assemblies и пакетов NuGet, которая отличается от схемы, используемой с предыдущим рядом выпусков, например, 6.9 и 6.10. Чтобы формировать Connector/NET 6.9 или 6.10 для использования с EF6, замените имена assembly и пакета в этой секции следующими:

Чтобы формировать Connector/NET для EF6:

  1. Отредактируйте секции конфигурации в файле app.config, чтобы добавить строку подключения и поставщика Connector/NET.

    <connectionStrings>
      <add name="MyContext" providerName="MySql.Data.MySqlClient"
          connectionString="server=localhost;port=3306;database=mycontext;uid=root;password=********"/>
    </connectionStrings>
    
    <entityFramework>
      <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
      <providers>
        <provider invariantName="MySql.Data.MySqlClient"
          type="MySql.Data.MySqlClient.MySqlProviderServices,
          MySql.Data.EntityFramework"/>
        <provider invariantName="System.Data.SqlClient"
          type="System.Data.Entity.SqlServer.SqlProviderServices,
          EntityFramework.SqlServer"/>
      </providers>
    </entityFramework>
    
  2. Примените ссылку на сборку, используя один из следующих методов:

  3. Установите новый класс DbConfiguration для MySQL. Этот шаг дополнительный, но наиболее рекомендуемый, потому что он добавляет все зависимости для классов MySQL. Это может быть сделано тремя способами:

    Также возможно создать класс DbConfiguration и добавить необходимые зависимости.

Возможности EF6

Следующее это новые особенности Entity Framework 6, реализованные в Connector/NET:

Возможности Code First

Следующее новые возможности Code First, поддержанные Connector/NET:

Пример применения EF6

Следующий пример кода C# представляет структуру модели Entity Framework 6.

using MySql.Data.Entity;
using System.Data.Common;
using System.Data.Entity;

namespace EF6
{
  // Code-Based Configuration and Dependency resolution
  [DbConfigurationType(typeof(MySqlEFConfiguration))]
  public class Parking : DbContext
  {
    public DbSet<Car> Cars { get; set; }
    public Parking() : base()
    {
    }
    // Constructor to use on a DbConnection that is already opened
    public Parking(DbConnection existingConnection, bool contextOwnsConnection)
           : base(existingConnection, contextOwnsConnection)
    {
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      base.OnModelCreating(modelBuilder);
      modelBuilder.Entity<Car>().MapToStoredProcedures();
    }
  }
  public class Car
  {
    public int CarId { get; set; }
    public string Model { get; set; }
    public int Year { get; set; }
    public string Manufacturer { get; set; }
  }
}

Пример кода C# показывает как использовать entities из предыдущей модели в приложении, которое хранит данные в таблице MySQL.

using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;

namespace EF6
{
  class Example
  {
    public static void ExecuteExample()
    {
      string connectionString = "server=localhost;port=3305;database=parking;uid=root";

      using (MySqlConnection connection = new MySqlConnection(connectionString))
      {
        // Create database if not exists
        using (Parking contextDB = new Parking(connection, false))
        {
          contextDB.Database.CreateIfNotExists();
        }
        connection.Open();
        MySqlTransaction transaction = connection.BeginTransaction();
        try
        {
          // DbConnection that is already opened
          using (Parking context = new Parking(connection, false))
          {
            // Interception/SQL logging
            context.Database.Log = (string message) => { Console.WriteLine(message); };
            // Passing an existing transaction to the context
            context.Database.UseTransaction(transaction);
            // DbSet.AddRange
            List<Car> cars = new List<Car>();
            cars.Add(new Car { Manufacturer = "Nissan", Model = "370Z", Year = 2012 });
            cars.Add(new Car { Manufacturer = "Ford", Model = "Mustang", Year = 2013 });
            cars.Add(new Car { Manufacturer = "Chevrolet", Model = "Camaro", Year = 2012 });
            cars.Add(new Car { Manufacturer = "Dodge", Model = "Charger", Year = 2013 });
            context.Cars.AddRange(cars);
            context.SaveChanges();
          }
          transaction.Commit();
        }
        catch
        {
          transaction.Rollback();
          throw;
        }
      }
    }
  }
}

7.2. Поддержка Entity Framework Core

MySQL Connector/NET объединяет поддержку Entity Framework Core (EF Core). Требования и конфигурация EF Core зависят от версии установленного Connector/NET и особенностей, которых вы требуете. Используйте эту таблицу, чтобы оценить минимальные требования.

Таблица 7.2. Версии Connector/NET и поддержка Entity Framework Core

Connector/NET EF Core 2.0 EF Core 2.1 EF Core 3.1.1
8.0.20 Не поддерживается. Не поддерживается. .NET Standard 2.0
С 8.0.18 до 8.0.19. Не поддерживается. .NET Standard 2.0 или .NET Framework 4.6.1 (и выше). Не поддерживается.
С 8.0.13 до 8.0.17. Не поддерживается. .NET Standard 2.0 или .NET Framework 4.6.1 (и выше). Не поддерживается.
С 8.0.11 до 8.0.12. .NET Standard 2.0; Не поддерживается Scaffolding. Не поддерживается.Не поддерживается.
6.10.8 .NET Standard 2.0 или .NET Framework 4.6.1 (и выше). Не поддерживается.Не поддерживается.
С 6.10.5 до 6.10.7. .NET Standard 2.0; Не поддерживается Scaffolding. Не поддерживается.Не поддерживается.

Минимальные требования для основной поддержки EF Core

Настройка с MySQL

Чтобы использовать Entity Framework Core с базой данных MySQL, сделайте следующее:

  1. Установите пакет NuGet MySql.Data.EntityFrameworkCore .

    Все пакеты установят дополнительные пакеты, требуемые, чтобы запустить ваше приложение. Для получения инструкций относительно добавления пакета NuGet см. соответствующую документацию Microsoft.

  2. В классе, который происходит из DbContext, перекройте метод OnConfiguring, чтобы установить провайдера данных MySQL с помощью UseMySQL. Следующий пример показывает, как установить поставщика, используя универсальную строку подключения в C#.

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      # warning To protect potentially sensitive information in your connection string,
        you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263
        for guidance on storing connection strings.
    
      optionsBuilder.UseMySQL("server=localhost;database=library;user=user;password=password");
    }
    

Ограничения

Реализация Connector/NET EF Core имеет следующие ограничения:

Максимальная длина строки

Следующая таблица показывает максимальную длину строковых типов, поддержанных Connector/NET в EF Core. Значения длины даны в байтах для типов строки, в зависимости от используемого набора символов.

Таблица 7.3. Максимум длины строк в Entity Framework Core

Тип данных Максимальная длина Тип в .NET
CHAR 255string
BINARY 255byte[]
VARCHAR, VARBINARY65,535 string, byte[]
TINYBLOB, TINYTEXT255 byte[]
BLOB, TEXT65,535 byte[]
MEDIUMBLOB, MEDIUMTEXT16,777,215 byte[]
LONGBLOB, LONGTEXT4,294,967,295 byte[]
ENUM65,535 string
SET 65,535string

Для получения дополнительной информации о требованиях к хранению строковых типов данных посмотрите String Type Storage Requirements.

7.2.1. Создание базы данных с Code First в EF Core

Code First позволяет вам определить модель entity в коде, создать базу данных из модели, а затем добавить данные. Данные, добавленные приложением, также могут быть получены с использованием MySQL Connector/NET.

Следующий пример показывает процесс создания базы данных из существующего кода. Хотя этот пример использует язык C#, можно выполнить его в Windows, macOS или Linux.

  1. Создайте консольное приложение для этого примера.

    1. Инициализируйте действительный проект .NET Core и консольное приложение, используя .NET Core command-line interface (CLI), а затем переключитесь на недавно созданный каталог (mysqlefcore).

      dotnet new console Б─⌠o mysqlefcore
      cd mysqlefcore
      
    2. Добавьте пакет MySql.Data.EntityFrameworkCore , используя CLI следующим образом:

      dotnet add package MySql.Data.EntityFrameworkCore --version 8.0.20
      

      Альтернативно, можно использовать Package Manager Console в Visual Studio, чтобы добавить пакет.

      Install-Package MySql.Data.EntityFrameworkCore -Version 8.0.20
      

      Версия (например, 8.0.20) должна соответствовать фактической версии Connector/NET. Для получения информации о текущей версии см. таблицу 7.2.

    3. Восстановите зависимости и определенные для проекта инструменты, которые определяются в файле проекта следующим образом:

      dotnet restore
      
  2. Создайте модель и запустите приложение.

    Модель в этом примере EF Core будет использоваться консольным приложением. Это состоит из двух entities, связанных с книжной библиотекой, которая будет формироваться в классе LibraryContext (или контексте базы данных).

    1. Создайте новый файл LibraryModel.cs и затем добавьте следующте классы Book и Publisher в пространство имен mysqlefcore.

      namespace mysqlefcore
      {
        public class Book
        {
          public string ISBN { get; set; }
          public string Title { get; set; }
          public string Author { get; set; }
          public string Language { get; set; }
          public int Pages { get; set; }
          public virtual Publisher Publisher { get; set; }
        }
        public class Publisher
        {
          public int ID { get; set; }
          public string Name { get; set; }
          public virtual ICollection<Book> Books { get; set; }
        }
      }
      
    2. Создайте новый файл LibraryContext.cs и добавьте код, который показан ниже. Замените универсальную строку подключения той, которая подходит для вашей конфигурации сервера MySQL.

      Класс LibraryContext содержит entities, чтобы использовать, и он позволяет конфигурацию определенных признаков модели, таких как Key, необходимые колонки, ссылки и так далее.

      using Microsoft.EntityFrameworkCore;
      using MySQL.Data.EntityFrameworkCore.Extensions;
      namespace mysqlefcore
      {
        public class LibraryContext : DbContext
        {
          public DbSet<Book> Book { get; set; }
          public DbSet<Publisher> Publisher { get; set; }
          protected override void OnConfiguring(DbContextOptionsBuilder
                                                optionsBuilder)
          {
            optionsBuilder.UseMySQL("server=localhost;database=library;user=user;password=password");
          }
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Publisher>(entity =>
            {
              entity.HasKey(e => e.ID);
              entity.Property(e => e.Name).IsRequired(); });
      
            modelBuilder.Entity<Book>(entity =>
            {
              entity.HasKey(e => e.ISBN);
              entity.Property(e => e.Title).IsRequired();
              entity.HasOne(d => d.Publisher).WithMany(p => p.Books); });
          }
        }
      }
      
    3. Введите следующий код в существующий файл Program.cs, заменяя код C# по умолчанию.

      using Microsoft.EntityFrameworkCore;
      using System;
      using System.Text;
      
      namespace mysqlefcore
      {
        class Program
        {
          static void Main(string[] args)
          {
            InsertData();
            PrintData();
          }
      
          private static void InsertData()
          {
            using(var context = new LibraryContext())
            {
              // Creates the database if not exists
              context.Database.EnsureCreated();
              // Adds a publisher
              var publisher = new Publisher
              {
                Name = "Mariner Books"
              };
              context.Publisher.Add(publisher);
              // Adds some books
              context.Book.Add(new Book
                {ISBN = "978-0544003415", Title = "The Lord of the Rings",
                 Author = "J.R.R. Tolkien", Language = "English", Pages = 1216,
                 Publisher = publisher});
              context.Book.Add(new Book
                {ISBN = "978-0547247762", Title = "The Sealed Letter",
                 Author = "Emma Donoghue", Language = "English",
                 Pages = 416, Publisher = publisher});
              // Saves changes
              context.SaveChanges();
            }
          }
      
          private static void PrintData()
          {
            // Gets and prints all books in database
            using (var context = new LibraryContext())
            {
              var books = context.Book.Include(p => p.Publisher);
              foreach(var book in books)
              {
                var data = new StringBuilder();
                data.AppendLine($"ISBN: {book.ISBN}");
                data.AppendLine($"Title: {book.Title}");
                data.AppendLine($"Publisher: {book.Publisher.Name}");
                Console.WriteLine(data.ToString());
              }
            }
          }
        }
      }
      
    4. Используйте следующие команды CLI, чтобы восстановить зависимости и затем запустить приложение.

      dotnet restore
      dotnet run
      

Вывод запуска приложения представляется следующим примером:

ISBN: 978-0544003415
Title: The Lord of the Rings
Publisher: Mariner Books

ISBN: 978-0547247762
Title: The Sealed Letter
Publisher: Mariner Books

7.2.2. Заготовки в существующей базы данных в EF Core

Заготовки базы данных создают модель Entity Framework из существующей базы данных. Получающиеся entities созданы и отображены к таблицам в указанной базе данных. Эта особенность была введена в MySQL Connector/NET 6.10.2-beta и 8.0.8-dmr, однако, они не поддерживаются всеми версиями Connector/NET (см. таблицу 7.2).

Пакет Design это часть главного пакета в EF Core 2.0 (и выше) и больше не отделяется. Если вы обновляетесь с EF Core 1.1 на EF Core 2.0 или 2.1, необходимо удалить вручную пакет MySql.Data.EntityFrameworkCore.Design.

Пакеты NuGet имеют способность выбрать лучшую цель проекта, что означает, что NuGet установит библиотеки, связанные с той определенной версией структуры.

Есть два различных пути к заготовкам в существующей базе данных:

Эта секция показывает как использовать базу данных sakila, используя оба подхода.

Минимальные требования

Модернизируя приложения ASP.NET Core до более новой структуры, надо использовать соответствующую версию EF Core (см. https://docs.microsoft.com/en-us/aspnet/core/migration/30-to-31?view=aspnetcore-3.1).

Использование .NET Core CLI

  1. Инициализируйте действительный проект .NET Core и консольное приложение, используя .NET Core command-line interface (CLI) и перейдите в созданный каталог (в данном случае это sakilaConsole).

    dotnet new console Б─⌠o sakilaConsole
    cd sakilaConsole
    
  2. Добавьте пакет MySQL NuGet для EF Core через CLI. Например, используйте следующую команду, чтобы добавить пакет MySql.Data.EntityFrameworkCore v8.0.20:

    dotnet add package MySql.Data.EntityFrameworkCore --version 8.0.20
    

    Версия (например, --version 8.0.20) должна соответствовать фактической версии Connector/NET. Для получения информации о текущей версии см. таблицу 7.2.

  3. Добавьте следующий пакет Nuget Microsoft.EntityFrameworkCore.Design:

    dotnet add package Microsoft.EntityFrameworkCore.Design
    
  4. При использовании EF Core 2.0, добавьте ссылку на Microsoft.EntityFrameworkCore.Tools.DotNet как запись DotNetCliToolReference в файле sakilaConsole.csproj:

    <ItemGroup>
      <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3"/>
    </ItemGroup>
    

    Инструменты .NET включены в .NET Core 2.1 SDK (и выше) и не требуются или поддерживаются для EF Core 2.1. Если это модернизация, удалите ссылку на тот пакет из файла .csproj (версия 2.0.3 в этом примере):

    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
    
  5. Восстановите зависимости и определенные для проекта инструменты, которые определяются в файле проекта следующим образом:

    dotnet restore
    
  6. Создайте модель Entity Framework Core, выполнив следующую команду (приспособьте значения строки подключения, чтобы соответствовать вашим параметрам настройки для опций user= и password=):

    dotnet ef dbcontext scaffold "server=localhost;port=3306;user=root;password=mypass;database=sakila" MySql.Data.EntityFrameworkCore -o sakila -f
    

    Чтобы утвердить, что модель была создана, откройте новый каталог sakila. Необходимо видеть, что файлы соответствуют всем таблицам, отображенным к entities. Кроме того, ищите файл sakilaContext.cs, который содержит DbContext для этой базы данных.

Применение Package Manager Console в Visual Studio

  1. Откройте Visual Studio и создайте новое Console App (.NET Core) для C#.

  2. Добавьте пакет MySQL NuGet для EF Core, используя Package Manager Console. Например, используйте следующую команду, чтобы добавить пакет MySql.Data.EntityFrameworkCore v8.0.20:

    Install-Package MySql.Data.EntityFrameworkCore -Version 8.0.20
    

    Версия (например, -Version 8.0.20 ) должна соответствовать фактической версии Connector/NET. См. таблицу 7.2 .

  3. Установите следующие пакеты NuGet, выбрав через Package Manager Console или Manage NuGet Packages for Solution из меню Tools и NuGet Package Manager:

  4. Откройте Package Manager Console и введите следующую команду, чтобы создать entities и DbContext для базы данных sakila (исправьте строку подключения, чтобы соответствовать вашим параметрам настройки для опций user= и password=):

    Scaffold-DbContext "server=localhost;port=3306;user=root;password=mypass;database=sakila" MySql.Data.EntityFrameworkCore -OutputDir sakila -f
    

    Visual Studio создает новый каталог sakila в проекте, который содержит все таблицы, отображенные к entities и файл sakilaContext.cs.

Заготовки базы данных, фильтруя таблицы

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

.NET Core CLI:

dotnet ef dbcontext scaffold \
       "server=localhost;port=3306;user=root;password=mypass; \
       database=sakila" MySql.Data.EntityFrameworkCore -o sakila \
       -t actor -t film -t film_actor -t language -f

Package Manager Console в Visual Studio:

Scaffold-DbContext "server=localhost;port=3306;user=root;\
                   password=mypass;\
                   database=sakila" MySql.Data.EntityFrameworkCore \
                   -OutputDir Sakila -Tables actor, film, \
                   film_actor, language -f

Заготовки с многочисленными схемами

Можно использовать больше, чем одну схему или базу данных. Обратите внимание на то, что у пользователя, применяемого, чтобы соединиться с сервером MySQL, должен быть доступ к каждой схеме, которая будет включена в контекст. Функциональность многократной схемы была введена в Connector/NET 6.10.3-rc и 8.0.9-dmr.

Следующие примеры командной строки показывают, как соединить схемы sakila и world в едином контексте.

.NET Core CLI:

dotnet ef dbcontext scaffold "server=localhost;port=3306;user=root; \
       password=mypass; \
       database=sakila" MySql.Data.EntityFrameworkCore -o sakila \
       --schema sakila --schema world -f

Package Manager Console в Visual Studio:

Scaffold-DbContext "server=localhost;port=3306;user=root; \
                   password=mypass;\
                   database=sakila" MySql.Data.EntityFrameworkCore \
                   -OutputDir Sakila -Schemas sakila, world -f

7.2.3. Формирование наборов символов и сопоставлений в EF Core

Эта секция описывает, как изменить набор символов и сопоставление в моделе Entity Framework (EF) Core. Модификации, сделанные к модели, затрагивают таблицы и колонки, произведенные из вашего кода.

Есть два отличных подхода, доступные для формирования наборов символов и сопоставлений в скриптах code first. Аннотация данных позволяет вам применить признаки непосредственно к вашей модели EF Core. Альтернативно, можно перекрыть метод OnModelCreating в вашем классе DbContext и использовать код fluent API, чтобы формировать определенные особенности модели. Пример каждого подхода показан ниже.

Для получения дополнительной информации о поддерживаемых наборах символов и сопоставлениях, посмотрите Character Sets and Collations in MySQL.

Использование аннотации данных

Прежде чем можно будет аннотировать модель EF Core набором символов и признаками сопоставления, добавьте ссылку на следующее пространство имен в файле, который содержит модель entity:

using MySql.Data.EntityFrameworkCore.DataAnnotations;

Добавьте один или больше признаков [MySqlCharset], чтобы хранить данные, используя множество наборов символов и один или больше признаков [MySqlCollation], чтобы выполнить сравнения согласно множеству сопоставлений. В следующем примере класс ComplexKey представляет entity (или таблицу), а Key1, Key2 и CollationColumn представляют свойства entity (или столбца).

[MySqlCharset("utf8")]
public class ComplexKey
{
  [MySqlCharset("latin1")
  public string Key1 { get; set; }
  [MySqlCharset("latin1")]
  public string Key2 { get; set; }
  [MySqlCollation("latin1_spanish_ci")]
  public string CollationColumn { get; set; }
}

Применение Code-First Fluent API

Добавьте следующую директиву, чтобы сослаться на методы, связанные с конфигурацией сопоставления и набором символов:

using MySQL.Data.EntityFrameworkCore.Extensions;

Используя fluent API, модель EF Core остается неизменной. Fluent API перекрывает любое правило, установленное признаком.

public class ComplexKey
{
  public string Key1 { get; set; }
  public string Key2 { get; set; }
  public string CollationColumn { get; set; }
}

В этом примере entity и различные свойства entity повторно формируются, включая обычные отображения к наборам символов и сопоставлениям. Этот подход использует методы ForMySQLHasCharset и ForMySQLHasCollation.

public class MyContext : DbContext
{
  public DbSet<ComplexKey> ComplexKeys { get; set; }

  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
    modelBuilder.Entity<ComplexKey>(e =>
    {
      e.HasKey(p => new { p.Key1, p.Key2 });
      e.ForMySQLHasCollation("ascii_bin");
      // defining collation at Entity level
      e.Property(p => p.Key1).ForMySQLHasCharset("latin1");
      // defining charset in a property
      e.Property(p => p.CollationColumnFA).ForMySQLHasCollation("utf8_bin");
      // defining collation in a property
    });
  }
}