Skip to content

Commit 5df763d

Browse files
committed
Check whether database provider is registered before registration of custom extensions
1 parent eef4d4a commit 5df763d

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

src/Thinktecture.EntityFrameworkCore.Relational/Extensions/RelationalDbContextOptionsBuilderExtensions.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,23 @@ public static TExtension TryAddExtension<TExtension>(this DbContextOptionsBuilde
172172
/// </summary>
173173
/// <param name="optionsBuilder">Options builder.</param>
174174
/// <param name="callback">Callback that updates the extension.</param>
175+
/// <param name="ensureDatabaseProviderRegistered">Indication whether to check whether a database provider is registered already.</param>
175176
/// <typeparam name="TExtension">Type of the extension.</typeparam>
176177
/// <exception cref="ArgumentNullException">
177178
/// <paramref name="optionsBuilder"/> is null
178179
/// - or
179180
/// <paramref name="callback"/> is null.
180181
/// </exception>
182+
/// <exception cref="InvalidOperationException">
183+
/// If <paramref name="ensureDatabaseProviderRegistered"/> is <c>true</c> and the database is not registered yet.
184+
/// </exception>
181185
public static TExtension AddOrUpdateExtension<TExtension>(
182186
this DbContextOptionsBuilder optionsBuilder,
183-
Action<TExtension> callback)
187+
Action<TExtension> callback,
188+
bool ensureDatabaseProviderRegistered = true)
184189
where TExtension : class, IDbContextOptionsExtension, new()
185190
{
186-
return AddOrUpdateExtension(optionsBuilder, callback, () => new TExtension());
191+
return AddOrUpdateExtension(optionsBuilder, callback, () => new TExtension(), ensureDatabaseProviderRegistered);
187192
}
188193

189194
/// <summary>
@@ -192,23 +197,31 @@ public static TExtension AddOrUpdateExtension<TExtension>(
192197
/// <param name="optionsBuilder">Options builder.</param>
193198
/// <param name="callback">Callback that updates the extension.</param>
194199
/// <param name="extensionFactory">Factory for creation of new instances of <typeparamref name="TExtension"/>.</param>
200+
/// <param name="ensureDatabaseProviderRegistered">Indication whether to check whether a database provider is registered already.</param>
195201
/// <typeparam name="TExtension">Type of the extension.</typeparam>
196202
/// <exception cref="ArgumentNullException">
197203
/// <paramref name="optionsBuilder"/> is null
198204
/// - or
199205
/// <paramref name="callback"/> is null.
200206
/// </exception>
207+
/// <exception cref="InvalidOperationException">
208+
/// If <paramref name="ensureDatabaseProviderRegistered"/> is <c>true</c> and the database is not registered yet.
209+
/// </exception>
201210
public static TExtension AddOrUpdateExtension<TExtension>(
202211
this DbContextOptionsBuilder optionsBuilder,
203212
Action<TExtension> callback,
204-
Func<TExtension> extensionFactory
213+
Func<TExtension> extensionFactory,
214+
bool ensureDatabaseProviderRegistered = true
205215
)
206216
where TExtension : class, IDbContextOptionsExtension
207217
{
208218
ArgumentNullException.ThrowIfNull(optionsBuilder);
209219
ArgumentNullException.ThrowIfNull(callback);
210220
ArgumentNullException.ThrowIfNull(extensionFactory);
211221

222+
if (ensureDatabaseProviderRegistered && !optionsBuilder.Options.Extensions.Any(e => e.Info.IsDatabaseProvider))
223+
throw new InvalidOperationException("Please register the database provider first (via 'UseSqlServer' or 'UseSqlite' etc).");
224+
212225
var extension = optionsBuilder.Options.FindExtension<TExtension>() ?? extensionFactory();
213226

214227
callback(extension);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Thinktecture.EntityFrameworkCore.Infrastructure;
2+
using Thinktecture.TestDatabaseContext;
3+
4+
namespace Thinktecture.Extensions.DbContextOptionsBuilderTests;
5+
6+
public class AddOrUpdateExtension
7+
{
8+
[Fact]
9+
public void Should_throw_if_database_provider_not_registered()
10+
{
11+
new DbContextOptionsBuilder<DbContextWithoutSchema>()
12+
.Invoking(b => b.AddOrUpdateExtension<RelationalDbContextOptionsExtension>(_ =>
13+
{
14+
}))
15+
.Should().Throw<InvalidOperationException>().WithMessage("Please register the database provider first (via 'UseSqlServer' or 'UseSqlite' etc).");
16+
}
17+
18+
[Fact]
19+
public void Should_not_throw_if_database_provider_is_registered_already()
20+
{
21+
new DbContextOptionsBuilder<DbContextWithoutSchema>()
22+
.UseSqlite("DataSource=:memory:")
23+
.Invoking(b => b.AddOrUpdateExtension<RelationalDbContextOptionsExtension>(_ =>
24+
{
25+
}))
26+
.Should().NotThrow();
27+
}
28+
29+
[Fact]
30+
public void Should_not_throw_if_called_inside_database_provider_specific_callback()
31+
{
32+
new DbContextOptionsBuilder<DbContextWithoutSchema>()
33+
.UseSqlite("DataSource=:memory:",
34+
sqliteBuilder => sqliteBuilder.Invoking(b => b.AddBulkOperationSupport()).Should().NotThrow());
35+
}
36+
}

0 commit comments

Comments
 (0)