MySQL Connector/NET 集成了对 Entity Framework 6 (EF6) 的支持,现在包括对使用 EF 6.4 版本进行跨平台应用程序部署的支持。本章介绍如何在 Connector/NET 中配置和使用 EF6 功能。
在本节中
Connector/NET 6.10 或 8.0.11
MySQL 服务器 5.6
Entity Framework 6 程序集
.NET Framework 4.6.2
Connector/NET 8.0.22
MySQL 服务器 5.6
Entity Framework 6.4 程序集
.NET Standard 2.1(.NET Core SDK 3.1 和 Visual Studio 2019 版本 16.5)
MySQL Connector/NET 8.0 发行系列对 EF6 程序集和 NuGet 包的命名方案与以前的发行系列(例如 6.9 和 6.10)不同。要配置 Connector/NET 6.9 或 6.10 以与 EF6 一起使用,请将本节中的程序集和包名称替换为以下名称
程序集:
MySql.Data.Entity.EF6
NuGet 包:
MySql.Data.Entity
有关
MySql.Data.Entity
NuGet 包及其用法的更多信息,请参见 https://nuget.net.cn/packages/MySql.Data.Entity/。
要配置 Connector/NET 对 EF6 的支持
编辑
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>
使用以下方法之一应用程序集引用
NuGet 包。 安装 NuGet 包以在安装期间自动将此引用添加到
app.config
或web.config
文件中。例如,要安装 Connector/NET 8.0.22 的包,请使用以下安装选项之一命令行界面 (CLI)
dotnet add package MySql.Data.EntityFramework -Version 8.0.22
包管理器控制台 (PMC)
Install-Package MySql.Data.EntityFramework -Version 8.0.22
使用 NuGet 包管理器的 Visual Studio。对于此选项,选择
nuget.org
作为包源,搜索mysql.data
,并安装MySql.Data.EntityFramework
的稳定版本。
MySQL Connector/NET MSI 文件。 安装 MySQL Connector/NET,然后将对
MySql.Data.EntityFramework
程序集的引用添加到您的项目中。根据使用的 .NET Framework 版本,程序集将从v4.0
、v4.5
或v4.8
文件夹中获取。MySQL Connector/NET 源代码。 从源代码构建 Connector/NET,然后将以下数据提供程序信息插入到
app.config
或web.config
文件中<system.data> <DbProviderFactories> <remove invariant="MySql.Data.MySqlClient" /> <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=8.0.22.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" /> </DbProviderFactories> </system.data>
重要始终将版本号更新为与
MySql.Data.dll
程序集中的版本号一致。
设置新的
DbConfiguration
类以用于 MySQL。此步骤是可选的,但强烈推荐,因为它为 MySQL 类添加了所有依赖关系解析器。这可以通过三种方式完成在上下文类上添加
DbConfigurationTypeAttribute
[DbConfigurationType(typeof(MySqlEFConfiguration))]
在应用程序启动时调用
DbConfiguration.SetConfiguration(new MySqlEFConfiguration())
。在配置文件中设置
DbConfiguration
类型<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.EntityFramework">
还可以创建自定义
DbConfiguration
类并添加所需的依赖关系解析器。
以下是 Connector/NET 中实现的 Entity Framework 6 中的新功能
跨平台支持 在 Connector/NET 8.0.22 中实现了 EF 6.4 作为初始提供程序版本,以包括与 Microsoft 的 .NET Standard 2.1 兼容的 Linux 和 macOS。
异步查询和保存 添加了对自 .NET 4.5 以来一直可用的基于任务的异步模式的支持。Connector/NET 支持的新异步方法是
ExecuteNonQueryAsync
ExecuteScalarAsync
PrepareAsync
连接弹性/重试逻辑 使得能够从瞬态连接故障中自动恢复。要使用此功能,请添加到
OnCreateModel
方法中SetExecutionStrategy(MySqlProviderInvariantName.ProviderName, () => new MySqlExecutionStrategy());
基于代码的配置 使您能够选择在代码中执行配置,而不是像传统方式那样在配置文件中执行配置。
依赖关系解析 引入了对服务定位器的支持。一些可以替换为自定义实现的功能已被分解。要添加依赖关系解析器,请使用
AddDependencyResolver(new MySqlDependencyResolver());
可以添加以下解析器
DbProviderFactory -> MySqlClientFactory
IDbConnectionFactory -> MySqlConnectionFactory
MigrationSqlGenerator -> MySqlMigrationSqlGenerator
DbProviderServices -> MySqlProviderServices
IProviderInvariantName -> MySqlProviderInvariantName
IDbProviderFactoryResolver -> MySqlProviderFactoryResolver
IManifestTokenResolver -> MySqlManifestTokenResolver
IDbModelCacheKey -> MySqlModelCacheKeyFactory
IDbExecutionStrategy -> MySqlExecutionStrategy
拦截/SQL 日志记录 提供用于拦截 Entity Framework 操作的低级构建块,并在其上构建简单的 SQL 日志记录
myContext.Database.Log = delegate(string message) { Console.Write(message); };
DbContext 现在可以使用已打开的 DbConnection 创建,这使那些希望在创建上下文时连接处于打开状态(例如,当您无法保证连接状态时在组件之间共享连接)的场景成为可能。
[DbConfigurationType(typeof(MySqlEFConfiguration))] class JourneyContext : DbContext { public DbSet<MyPlace> MyPlaces { get; set; } public JourneyContext() : base() { } public JourneyContext(DbConnection existingConnection, bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection) { } } using (MySqlConnection conn = new MySqlConnection("<connectionString>")) { conn.Open(); ... using (var context = new JourneyContext(conn, false)) { ... } }
改进的事务支持 提供了对框架外部事务的支持,以及在 Entity Framework 中创建事务的改进方法。从 Entity Framework 6 开始,
Database.ExecuteSqlCommand()
默认情况下会在没有现有事务的情况下将命令包装在事务中。此方法有一些重载,允许用户根据需要覆盖此行为。通过 API(例如ObjectContext.ExecuteFunction()
)包含在模型中的存储过程的执行也是如此。也可以将现有事务传递给上下文。DbSet.AddRange/RemoveRange 提供了一种优化的方法来将多个实体添加到集合或从集合中删除多个实体。
以下是 Connector/NET 支持的新 Code First 功能
Code First 映射到插入/更新/删除存储过程 支持
modelBuilder.Entity<EntityType>().MapToStoredProcedures();
幂等迁移脚本 允许您生成一个可以将数据库升级到任何版本的 SQL 脚本,直到最新版本。为此,请在包管理器控制台中运行
Update-Database -Script -SourceMigration: $InitialDatabase
命令。可配置的迁移历史记录表 允许您自定义迁移历史记录表的定义。
以下 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# 代码示例展示了如何在将数据存储在 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;
}
}
}
}
}