Skip to content

Commit

Permalink
Allow DbConnection or connection string to be changed on existing DbC…
Browse files Browse the repository at this point in the history
…ontext

Closes npgsql#1174
Following dotnet/efcore#8427

WIP: Tests are failing because of dotnet/efcore#19707
  • Loading branch information
roji committed Jan 25, 2020
1 parent 3b9eef3 commit 099f281
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 9 deletions.
83 changes: 74 additions & 9 deletions src/EFCore.PG/Extensions/NpgsqlDbContextOptionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Data.Common;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
Expand All @@ -15,11 +16,40 @@ namespace Microsoft.EntityFrameworkCore
/// </summary>
public static class NpgsqlDbContextOptionsExtensions
{
/// <summary>
/// <para>
/// Configures the context to connect to a PostgreSQL server with Npgsql, but without initially setting any
/// <see cref="DbConnection" /> or connection string.
/// </para>
/// <para>
/// The connection or connection string must be set before the <see cref="DbContext" /> is used to connect
/// to a database. Set a connection using <see cref="RelationalDatabaseFacadeExtensions.SetDbConnection" />.
/// Set a connection string using <see cref="RelationalDatabaseFacadeExtensions.SetConnectionString" />.
/// </para>
/// </summary>
/// <param name="optionsBuilder">The builder being used to configure the context.</param>
/// <param name="npgsqlOptionsAction">An optional action to allow additional Npgsql-specific configuration.</param>
/// <returns>The options builder so that further configuration can be chained.</returns>
public static DbContextOptionsBuilder UseNpgsql(
[NotNull] this DbContextOptionsBuilder optionsBuilder,
[CanBeNull] Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
{
Check.NotNull(optionsBuilder, nameof(optionsBuilder));

((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(GetOrCreateExtension(optionsBuilder));

ConfigureWarnings(optionsBuilder);

npgsqlOptionsAction?.Invoke(new NpgsqlDbContextOptionsBuilder(optionsBuilder));

return optionsBuilder;
}

/// <summary>
/// Configures the context to connect to a PostgreSQL database with Npgsql.
/// </summary>
/// <param name="optionsBuilder"> A builder for setting options on the context. </param>
/// <param name="connectionString"> The connection string of the database to connect to. </param>
/// <param name="optionsBuilder">A builder for setting options on the context.</param>
/// <param name="connectionString">The connection string of the database to connect to.</param>
/// <param name="npgsqlOptionsAction">An optional action to allow additional Npgsql-specific configuration.</param>
/// <returns>
/// The options builder so that further configuration can be chained.
Expand All @@ -36,6 +66,8 @@ public static DbContextOptionsBuilder UseNpgsql(
var extension = (NpgsqlOptionsExtension)GetOrCreateExtension(optionsBuilder).WithConnectionString(connectionString);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);

ConfigureWarnings(optionsBuilder);

npgsqlOptionsAction?.Invoke(new NpgsqlDbContextOptionsBuilder(optionsBuilder));

return optionsBuilder;
Expand All @@ -44,7 +76,7 @@ public static DbContextOptionsBuilder UseNpgsql(
/// <summary>
/// Configures the context to connect to a PostgreSQL database with Npgsql.
/// </summary>
/// <param name="optionsBuilder"> A builder for setting options on the context. </param>
/// <param name="optionsBuilder">A builder for setting options on the context.</param>
/// <param name="connection">
/// An existing <see cref="DbConnection" /> to be used to connect to the database. If the connection is
/// in the open state then EF will not open or close the connection. If the connection is in the closed
Expand All @@ -71,11 +103,32 @@ public static DbContextOptionsBuilder UseNpgsql(
return optionsBuilder;
}

/// <summary>
/// <para>
/// Configures the context to connect to a PostgreSQL server with Npgsql, but without initially setting any
/// <see cref="DbConnection" /> or connection string.
/// </para>
/// <para>
/// The connection or connection string must be set before the <see cref="DbContext" /> is used to connect
/// to a database. Set a connection using <see cref="RelationalDatabaseFacadeExtensions.SetDbConnection" />.
/// Set a connection string using <see cref="RelationalDatabaseFacadeExtensions.SetConnectionString" />.
/// </para>
/// </summary>
/// <param name="optionsBuilder">The builder being used to configure the context.</param>
/// <param name="npgsqlOptionsAction">An optional action to allow additional Npgsql-specific configuration.</param>
/// <returns>The options builder so that further configuration can be chained.</returns>
public static DbContextOptionsBuilder<TContext> UseSqlServer<TContext>(
[NotNull] this DbContextOptionsBuilder<TContext> optionsBuilder,
[CanBeNull] Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
where TContext : DbContext
=> (DbContextOptionsBuilder<TContext>)UseNpgsql(
(DbContextOptionsBuilder)optionsBuilder, npgsqlOptionsAction);

/// <summary>
/// Configures the context to connect to a PostgreSQL database with Npgsql.
/// </summary>
/// <param name="optionsBuilder"> A builder for setting options on the context. </param>
/// <param name="connectionString"> The connection string of the database to connect to. </param>
/// <param name="optionsBuilder">A builder for setting options on the context.</param>
/// <param name="connectionString">The connection string of the database to connect to.</param>
/// <param name="npgsqlOptionsAction">An optional action to allow additional Npgsql-configuration.</param>
/// <returns>
/// The options builder so that further configuration can be chained.
Expand All @@ -92,9 +145,9 @@ public static DbContextOptionsBuilder<TContext> UseNpgsql<TContext>(
/// <summary>
/// Configures the context to connect to a PostgreSQL database with Npgsql.
/// </summary>
/// <param name="optionsBuilder"> A builder for setting options on the context. </param>
/// <param name="optionsBuilder">A builder for setting options on the context.</param>
/// <param name="connection">
/// An existing <see cref="DbConnection" /> to be used to connect to the database. If the connection is
/// An existing <see cref="DbConnection" />to be used to connect to the database. If the connection is
/// in the open state then EF will not open or close the connection. If the connection is in the closed
/// state then EF will open and close the connection as needed.
/// </param>
Expand All @@ -118,10 +171,22 @@ public static DbContextOptionsBuilder<TContext> UseNpgsql<TContext>(
/// <returns>
/// An existing instance of <see cref="NpgsqlOptionsExtension"/>, or a new instance if one does not exist.
/// </returns>
[NotNull]
private static NpgsqlOptionsExtension GetOrCreateExtension([NotNull] DbContextOptionsBuilder optionsBuilder)
static NpgsqlOptionsExtension GetOrCreateExtension(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.Options.FindExtension<NpgsqlOptionsExtension>() is NpgsqlOptionsExtension existing
? new NpgsqlOptionsExtension(existing)
: new NpgsqlOptionsExtension();

static void ConfigureWarnings(DbContextOptionsBuilder optionsBuilder)
{
var coreOptionsExtension
= optionsBuilder.Options.FindExtension<CoreOptionsExtension>()
?? new CoreOptionsExtension();

coreOptionsExtension = coreOptionsExtension.WithWarningsConfiguration(
coreOptionsExtension.WarningsConfiguration.TryWithExplicit(
RelationalEventId.AmbientTransactionWarning, WarningBehavior.Throw));

((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(coreOptionsExtension);
}
}
}
29 changes: 29 additions & 0 deletions test/EFCore.PG.FunctionalTests/TwoDatabasesNpgsqlTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities;
using Xunit;

namespace Npgsql.EntityFrameworkCore.PostgreSQL
{
public class TwoDatabasesNpgsqlTest : TwoDatabasesTestBase, IClassFixture<NpgsqlFixture>
{
public TwoDatabasesNpgsqlTest(NpgsqlFixture fixture)
: base(fixture)
{
}

protected new NpgsqlFixture Fixture => (NpgsqlFixture)base.Fixture;

protected override DbContextOptionsBuilder CreateTestOptions(
DbContextOptionsBuilder optionsBuilder, bool withConnectionString = false)
=> withConnectionString
? optionsBuilder.UseNpgsql(DummyConnectionString)
: optionsBuilder.UseNpgsql();

protected override TwoDatabasesWithDataContext CreateBackingContext(string databaseName)
=> new TwoDatabasesWithDataContext(Fixture.CreateOptions(NpgsqlTestStore.Create(databaseName)));

protected override string DummyConnectionString { get; } = "Database=DoesNotExist";
}
}

0 comments on commit 099f281

Please sign in to comment.