Skip to content

Commit

Permalink
Add support for AddMySql() method. (PomeloFoundation#1693)
Browse files Browse the repository at this point in the history
Improve support for null connection strings.
  • Loading branch information
lauxjpn authored Jul 26, 2022
1 parent 0ea6b30 commit 02f00e7
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,27 @@ public static DbContextOptionsBuilder UseMySql(
/// <returns> The options builder so that further configuration can be chained. </returns>
public static DbContextOptionsBuilder UseMySql(
[NotNull] this DbContextOptionsBuilder optionsBuilder,
[NotNull] string connectionString,
[CanBeNull] string connectionString,
[NotNull] ServerVersion serverVersion,
[CanBeNull] Action<MySqlDbContextOptionsBuilder> mySqlOptionsAction = null)
{
Check.NotNull(optionsBuilder, nameof(optionsBuilder));
Check.NotEmpty(connectionString, nameof(connectionString));

var resolvedConnectionString = new NamedConnectionStringResolver(optionsBuilder.Options)
.ResolveConnectionString(connectionString);
Check.NullButNotEmpty(connectionString, nameof(connectionString));

var csb = new MySqlConnectionStringBuilder(resolvedConnectionString)
if (connectionString is not null)
{
AllowUserVariables = true,
UseAffectedRows = false
};
var resolvedConnectionString = new NamedConnectionStringResolver(optionsBuilder.Options)
.ResolveConnectionString(connectionString);

resolvedConnectionString = csb.ConnectionString;
// TODO: Move to MySqlRelationalConnection.
var csb = new MySqlConnectionStringBuilder(resolvedConnectionString) { AllowUserVariables = true, UseAffectedRows = false };

connectionString = csb.ConnectionString;
}

var extension = (MySqlOptionsExtension)GetOrCreateExtension(optionsBuilder)
.WithServerVersion(serverVersion)
.WithConnectionString(resolvedConnectionString);
.WithConnectionString(connectionString);

((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
ConfigureWarnings(optionsBuilder);
Expand Down Expand Up @@ -160,6 +160,7 @@ public static DbContextOptionsBuilder UseMySql(
.ResolveConnectionString(connection.ConnectionString)
: null;

// TODO: Move to MySqlRelationalConnection.
var csb = new MySqlConnectionStringBuilder(resolvedConnectionString);

if (!csb.AllowUserVariables ||
Expand Down
62 changes: 62 additions & 0 deletions src/EFCore.MySql/Extensions/MySqlServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// Copyright (c) Pomelo Foundation. All rights reserved.
// Licensed under the MIT. See LICENSE in the project root for license information.

using System;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Pomelo.EntityFrameworkCore.MySql.Internal;
using Pomelo.EntityFrameworkCore.MySql.Migrations.Internal;
using Pomelo.EntityFrameworkCore.MySql.Storage.Internal;
using Pomelo.EntityFrameworkCore.MySql.Update.Internal;
using Pomelo.EntityFrameworkCore.MySql.ValueGeneration.Internal;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Migrations;
Expand All @@ -20,6 +22,7 @@
using Pomelo.EntityFrameworkCore.MySql.Diagnostics.Internal;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal;
using Pomelo.EntityFrameworkCore.MySql.Migrations;
using Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal;
Expand All @@ -30,6 +33,65 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class MySqlServiceCollectionExtensions
{
/// <summary>
/// <para>
/// Registers the given Entity Framework context as a service in the <see cref="IServiceCollection" />
/// and configures it to connect to a MySQL compatible database.
/// </para>
/// <para>
/// Use this method when using dependency injection in your application, such as with ASP.NET Core.
/// For applications that don't use dependency injection, consider creating <see cref="DbContext" />
/// instances directly with its constructor. The <see cref="DbContext.OnConfiguring" /> method can then be
/// overridden to configure the Pomelo.EntityFrameworkCore.MySql provider and connection string.
/// </para>
/// <para>
/// To configure the <see cref="DbContextOptions{TContext}" /> for the context, either override the
/// <see cref="DbContext.OnConfiguring" /> method in your derived context, or supply
/// an optional action to configure the <see cref="DbContextOptions" /> for the context.
/// </para>
/// <para>
/// For more information on how to use this method, see the Entity Framework Core documentation at https://aka.ms/efdocs.
/// For more information on using dependency injection, see https://go.microsoft.com/fwlink/?LinkId=526890.
/// </para>
/// </summary>
/// <typeparam name="TContext"> The type of context to be registered. </typeparam>
/// <param name="serviceCollection"> The <see cref="IServiceCollection" /> to add services to. </param>
/// <param name="connectionString"> The connection string of the database to connect to. </param>
/// <param name="serverVersion">
/// <para>
/// The version of the database server.
/// </para>
/// <para>
/// Create an object for this parameter by calling the static method
/// <see cref="ServerVersion.Create(System.Version,ServerType)"/>,
/// by calling the static method <see cref="ServerVersion.AutoDetect(string)"/> (which retrieves the server version directly
/// from the database server),
/// by parsing a version string using the static methods
/// <see cref="ServerVersion.Parse(string)"/> or <see cref="ServerVersion.TryParse(string,out ServerVersion)"/>,
/// or by directly instantiating an object from the <see cref="MySqlServerVersion"/> (for MySQL) or
/// <see cref="MariaDbServerVersion"/> (for MariaDB) classes.
/// </para>
/// </param>
/// <param name="mySqlOptionsAction"> An optional action to allow additional MySQL specific configuration. </param>
/// <param name="optionsAction"> An optional action to configure the <see cref="DbContextOptions" /> for the context. </param>
/// <returns> The same service collection so that multiple calls can be chained. </returns>
public static IServiceCollection AddMySql<TContext>(
this IServiceCollection serviceCollection,
string connectionString,
ServerVersion serverVersion,
Action<MySqlDbContextOptionsBuilder> mySqlOptionsAction = null,
Action<DbContextOptionsBuilder> optionsAction = null)
where TContext : DbContext
{
Check.NotNull(serviceCollection, nameof(serviceCollection));

return serviceCollection.AddDbContext<TContext>((_, options) =>
{
optionsAction?.Invoke(options);
options.UseMySql(connectionString, serverVersion, mySqlOptionsAction);
});
}

public static IServiceCollection AddEntityFrameworkMySql([NotNull] this IServiceCollection serviceCollection)
{
Check.NotNull(serviceCollection, nameof(serviceCollection));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public virtual IMySqlRelationalConnection CreateMasterConnection()
set => base.DbConnection = value;
}

private MySqlConnectionStringBuilder AddConnectionStringOptions(MySqlConnectionStringBuilder builder)
protected virtual MySqlConnectionStringBuilder AddConnectionStringOptions(MySqlConnectionStringBuilder builder)
{
if (CommandTimeout != null)
{
Expand Down
48 changes: 48 additions & 0 deletions test/EFCore.MySql.Tests/MySqlDbContextOptionsExtensionsTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.TestModels.ConferencePlanner;
using Microsoft.Extensions.DependencyInjection;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Pomelo.EntityFrameworkCore.MySql.Internal;
Expand Down Expand Up @@ -367,5 +370,50 @@ public void UseMySql_without_connection_explicit_DefaultDataTypeMappings_is_appl

Assert.Equal(MySqlBooleanType.Bit1, mySqlOptions.DefaultDataTypeMappings.ClrBoolean);
}

[ConditionalTheory]
[InlineData(false)]
[InlineData(true)]
public void Service_collection_extension_method_can_configure_provider_options(bool nullConnectionString)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddMySql<ApplicationDbContext>(
nullConnectionString
? null
: AppConfig.ConnectionString,
AppConfig.ServerVersion,
mySqlOption =>
{
mySqlOption.MaxBatchSize(123);
mySqlOption.CommandTimeout(30);
},
dbContextOption =>
{
dbContextOption.EnableDetailedErrors();
});

var services = serviceCollection.BuildServiceProvider();

using (var serviceScope = services
.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
var coreOptions = serviceScope.ServiceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>().GetExtension<CoreOptionsExtension>();
Assert.True(coreOptions.DetailedErrorsEnabled);

var mySqlOptions = serviceScope.ServiceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>().GetExtension<MySqlOptionsExtension>();
Assert.Equal(123, mySqlOptions.MaxBatchSize);
Assert.Equal(30, mySqlOptions.CommandTimeout);

if (nullConnectionString)
{
Assert.Equal(null, mySqlOptions.ConnectionString);
}
else
{
Assert.StartsWith(AppConfig.ConnectionString, mySqlOptions.ConnectionString);
}
}
}
}
}

0 comments on commit 02f00e7

Please sign in to comment.