diff --git a/Directory.Packages.props b/Directory.Packages.props index 5d9885ddbd..5a3c4bdd7e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -136,7 +136,8 @@ - + + @@ -185,4 +186,4 @@ - \ No newline at end of file + diff --git a/docs/en/framework/data/entity-framework-core/mysql.md b/docs/en/framework/data/entity-framework-core/mysql.md index 7760598414..8f299bdee4 100644 --- a/docs/en/framework/data/entity-framework-core/mysql.md +++ b/docs/en/framework/data/entity-framework-core/mysql.md @@ -17,10 +17,20 @@ Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFra Find `UseSqlServer()` calls in your solution. Check the following files: * *YourProjectName*EntityFrameworkCoreModule.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySQL()`. -* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySql()`. Then add a new parameter (`ServerVersion`) to `UseMySql()` method. Example: `.UseMySql(configuration.GetConnectionString("Default"), ServerVersion.Parse("8.0.21-mysql"))`. See [this issue](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/pull/1233) for more information about `ServerVersion`) +* *YourProjectName*DbContextFactory.cs inside the `.EntityFrameworkCore` project. Replace `UseSqlServer()` with `UseMySQL()`. > Depending on your solution structure, you may find more code files need to be changed. +## Use Pomelo Provider + +Alternatively, you can use the [Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql) provider. Replace the [Volo.Abp.EntityFrameworkCore.MySQL](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL) package with the [Volo.Abp.EntityFrameworkCore.MySQL.Pomelo](https://www.nuget.org/packages/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo) package in your `.EntityFrameworkCore` project. + +Find ***YourProjectName*EntityFrameworkCoreModule** class inside the `.EntityFrameworkCore` project, replace `typeof(AbpEntityFrameworkCoreMySQLModule)` with `typeof(AbpEntityFrameworkCoreMySQLPomeloModule)` in the `DependsOn` attribute. + +> Depending on your solution structure, you may find more code files need to be changed. + +The `UseMySQL()` method calls remain the same, no changes needed. + ## Change the Connection Strings MySQL connection strings are different than SQL Server connection strings. So, check all `appsettings.json` files in your solution and replace the connection strings inside them. See the [connectionstrings.com](https://www.connectionstrings.com/mysql) for details of MySQL connection string options. diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 78f7ae0011..4167492d16 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -491,6 +491,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Bunny. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Timing.Tests", "test\Volo.Abp.Timing.Tests\Volo.Abp.Timing.Tests.csproj", "{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EntityFrameworkCore.MySQL.Pomelo", "src\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj", "{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1465,6 +1467,10 @@ Global {58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Debug|Any CPU.Build.0 = Debug|Any CPU {58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.ActiveCfg = Release|Any CPU {58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.Build.0 = Release|Any CPU + {5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1712,6 +1718,7 @@ Global {1BBCBA72-CDB6-4882-96EE-D4CD149433A2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915} = {447C8A77-E5F0-4538-8687-7383196D04EA} {58FCF22D-E8DB-4EB8-B586-9BB6E9899D64} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {5B49FE47-A4C5-45BE-A903-8215CF5E2FAF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xml b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xml new file mode 100644 index 0000000000..1715698ccd --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xsd b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xsd new file mode 100644 index 0000000000..ffa6fc4b78 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Microsoft/EntityFrameworkCore/AbpMySqlModelBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Microsoft/EntityFrameworkCore/AbpPomeloMySQLModelBuilderExtensions.cs similarity index 100% rename from framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Microsoft/EntityFrameworkCore/AbpMySqlModelBuilderExtensions.cs rename to framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Microsoft/EntityFrameworkCore/AbpPomeloMySQLModelBuilderExtensions.cs diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj new file mode 100644 index 0000000000..f92e905688 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj @@ -0,0 +1,27 @@ + + + + + + + net9.0 + enable + Nullable + Volo.Abp.EntityFrameworkCore.MySQL.Pomelo + Volo.Abp.EntityFrameworkCore.MySQL.Pomelo + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + + + diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs new file mode 100644 index 0000000000..9f26be0cf0 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs @@ -0,0 +1,33 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp.EntityFrameworkCore.DependencyInjection; + +namespace Volo.Abp.EntityFrameworkCore; + +public static class AbpDbContextConfigurationContextMySQLExtensions +{ + public static DbContextOptionsBuilder UseMySQL( + [NotNull] this AbpDbContextConfigurationContext context, + Action? mySQLOptionsAction = null) + { + if (context.ExistingConnection != null) + { + return context.DbContextOptions.UseMySql(context.ExistingConnection, + ServerVersion.AutoDetect(context.ConnectionString), optionsBuilder => + { + optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); + mySQLOptionsAction?.Invoke(optionsBuilder); + }); + } + else + { + return context.DbContextOptions.UseMySql(context.ConnectionString, + ServerVersion.AutoDetect(context.ConnectionString), optionsBuilder => + { + optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); + mySQLOptionsAction?.Invoke(optionsBuilder); + }); + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs new file mode 100644 index 0000000000..67d76fb0a9 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using System; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Volo.Abp.EntityFrameworkCore; + +public static class AbpDbContextOptionsMySQLExtensions +{ + public static void UseMySQL( + [NotNull] this AbpDbContextOptions options, + Action? mySQLOptionsAction = null) + { + options.Configure(context => + { + context.UseMySQL(mySQLOptionsAction); + }); + } + + public static void UseMySQL( + [NotNull] this AbpDbContextOptions options, + Action? mySQLOptionsAction = null) + where TDbContext : AbpDbContext + { + options.Configure(context => + { + context.UseMySQL(mySQLOptionsAction); + }); + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/ConnectionStrings/PomeloMySQLConnectionStringChecker.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/ConnectionStrings/PomeloMySQLConnectionStringChecker.cs new file mode 100644 index 0000000000..2d7beee20b --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/ConnectionStrings/PomeloMySQLConnectionStringChecker.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using MySqlConnector; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.EntityFrameworkCore.ConnectionStrings; + +[Dependency(ReplaceServices = true)] +public class PomeloMySQLConnectionStringChecker : IConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new AbpConnectionStringCheckResult(); + try + { + var connString = new MySqlConnectionStringBuilder(connectionString) + { + ConnectionLifeTime = 1 + }; + + var oldDatabaseName = connString.Database; + connString.Database = "mysql"; + + await using var conn = new MySqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception) + { + return result; + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/MySQL/AbpEntityFrameworkCoreMySQLPomeloModule.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/MySQL/AbpEntityFrameworkCoreMySQLPomeloModule.cs new file mode 100644 index 0000000000..9d0a473af2 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo/Volo/Abp/EntityFrameworkCore/MySQL/AbpEntityFrameworkCoreMySQLPomeloModule.cs @@ -0,0 +1,27 @@ +using Volo.Abp.EntityFrameworkCore.GlobalFilters; +using Volo.Abp.Guids; +using Volo.Abp.Modularity; + +namespace Volo.Abp.EntityFrameworkCore.MySQL; + +[DependsOn( + typeof(AbpEntityFrameworkCoreModule) + )] +public class AbpEntityFrameworkCoreMySQLPomeloModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + if (options.DefaultSequentialGuidType == null) + { + options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString; + } + }); + + Configure(options => + { + options.UseDbFunction = true; + }); + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Microsoft/EntityFrameworkCore/AbpMySQLModelBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Microsoft/EntityFrameworkCore/AbpMySQLModelBuilderExtensions.cs new file mode 100644 index 0000000000..dc5d1b4f0d --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Microsoft/EntityFrameworkCore/AbpMySQLModelBuilderExtensions.cs @@ -0,0 +1,12 @@ +using Volo.Abp.EntityFrameworkCore; + +namespace Microsoft.EntityFrameworkCore; + +public static class AbpMySQLModelBuilderExtensions +{ + public static void UseMySQL( + this ModelBuilder modelBuilder) + { + modelBuilder.SetDatabaseProvider(EfCoreDatabaseProvider.MySql); + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj index 3b039a3ef0..07b8ad1563 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo.Abp.EntityFrameworkCore.MySQL.csproj @@ -21,7 +21,7 @@ - + diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs index 07381983ca..b869109a80 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextConfigurationContextMySQLExtensions.cs @@ -1,7 +1,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using System; -using Microsoft.EntityFrameworkCore.Infrastructure; using Volo.Abp.EntityFrameworkCore.DependencyInjection; namespace Volo.Abp.EntityFrameworkCore; @@ -9,26 +8,16 @@ namespace Volo.Abp.EntityFrameworkCore; public static class AbpDbContextConfigurationContextMySQLExtensions { public static DbContextOptionsBuilder UseMySQL( - [NotNull] this AbpDbContextConfigurationContext context, - Action? mySQLOptionsAction = null) + [NotNull] this AbpDbContextConfigurationContext context, + Action? mySQLOptionsAction = null) { if (context.ExistingConnection != null) { - return context.DbContextOptions.UseMySql(context.ExistingConnection, - ServerVersion.AutoDetect(context.ConnectionString), optionsBuilder => - { - optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); - mySQLOptionsAction?.Invoke(optionsBuilder); - }); + return context.DbContextOptions.UseMySQL(context.ExistingConnection, mySQLOptionsAction); } else { - return context.DbContextOptions.UseMySql(context.ConnectionString, - ServerVersion.AutoDetect(context.ConnectionString), optionsBuilder => - { - optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); - mySQLOptionsAction?.Invoke(optionsBuilder); - }); + return context.DbContextOptions.UseMySQL(context.ConnectionString, mySQLOptionsAction); } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs index baf8c53a14..cdd8beebde 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/AbpDbContextOptionsMySQLExtensions.cs @@ -1,14 +1,13 @@ using JetBrains.Annotations; using System; -using Microsoft.EntityFrameworkCore.Infrastructure; namespace Volo.Abp.EntityFrameworkCore; public static class AbpDbContextOptionsMySQLExtensions { public static void UseMySQL( - [NotNull] this AbpDbContextOptions options, - Action? mySQLOptionsAction = null) + [NotNull] this AbpDbContextOptions options, + Action? mySQLOptionsAction = null) { options.Configure(context => { @@ -18,7 +17,7 @@ public static class AbpDbContextOptionsMySQLExtensions public static void UseMySQL( [NotNull] this AbpDbContextOptions options, - Action? mySQLOptionsAction = null) + Action? mySQLOptionsAction = null) where TDbContext : AbpDbContext { options.Configure(context => diff --git a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySqlConnectionStringChecker.cs b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySQLConnectionStringChecker.cs similarity index 91% rename from framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySqlConnectionStringChecker.cs rename to framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySQLConnectionStringChecker.cs index 88dc7912f3..8dca9074dc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySqlConnectionStringChecker.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore.MySQL/Volo/Abp/EntityFrameworkCore/ConnectionStrings/MySQLConnectionStringChecker.cs @@ -1,13 +1,13 @@ using System; using System.Threading.Tasks; -using MySqlConnector; +using MySql.Data.MySqlClient; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; namespace Volo.Abp.EntityFrameworkCore.ConnectionStrings; [Dependency(ReplaceServices = true)] -public class MySqlConnectionStringChecker : IConnectionStringChecker, ITransientDependency +public class MySQLConnectionStringChecker : IConnectionStringChecker, ITransientDependency { public virtual async Task CheckAsync(string connectionString) { diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index e916a379d2..9dbce186ee 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -178,6 +178,7 @@ $projects = ( "framework/src/Volo.Abp.Emailing", "framework/src/Volo.Abp.EntityFrameworkCore", "framework/src/Volo.Abp.EntityFrameworkCore.MySQL", + "framework/src/Volo.Abp.EntityFrameworkCore.MySQL.Pomelo", "framework/src/Volo.Abp.EntityFrameworkCore.Oracle", "framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart", "framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql",