Skip to content

Commit

Permalink
Add sugar for determining the database provider in use
Browse files Browse the repository at this point in the history
Part of #7166

Main scenario here is conditional behavior in OnModelCreating now that we build a different model per provider.
  • Loading branch information
ajcvickers committed May 23, 2017
1 parent 76825c2 commit b9cd36d
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 3 deletions.
36 changes: 36 additions & 0 deletions src/EFCore.InMemory/Extensions/InMemoryDatabaseFacadeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// In-memory specific extension methods for <see cref="DbContext.Database" />.
/// </summary>
public static class InMemoryDatabaseFacadeExtensions
{
/// <summary>
/// <para>
/// Returns true if the database provider currently in use is the in-memory provider.
/// </para>
/// <para>
/// This method can only be used after the <see cref="DbContext" /> has been configured because
/// it is only then that the provider is known. This means that this method cannot be used
/// in <see cref="DbContext.OnConfiguring" /> because this is where application code sets the
/// provider to use as part of configuring the context.
/// </para>
/// </summary>
/// <param name="database"> The facade from <see cref="DbContext.Database" />. </param>
/// <returns> True if the in-memory database is being used; false otherwise. </returns>
public static bool IsInMemory([NotNull] this DatabaseFacade database)
=> database.ProviderName.Equals(
typeof(InMemoryOptionsExtension).GetTypeInfo().Assembly.GetName().Name,
StringComparison.Ordinal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Utilities;

// ReSharper disable once CheckNamespace
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;

namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// SQL Server specific extension methods for <see cref="DbContext.Database" />.
/// </summary>
public static class SqlServerDatabaseFacadeExtensions
{
/// <summary>
/// <para>
/// Returns true if the database provider currently in use is the SQL Server provider.
/// </para>
/// <para>
/// This method can only be used after the <see cref="DbContext" /> has been configured because
/// it is only then that the provider is known. This means that this method cannot be used
/// in <see cref="DbContext.OnConfiguring" /> because this is where application code sets the
/// provider to use as part of configuring the context.
/// </para>
/// </summary>
/// <param name="database"> The facade from <see cref="DbContext.Database" />. </param>
/// <returns> True if SQL Server is being used; false otherwise. </returns>
public static bool IsSqlServer([NotNull] this DatabaseFacade database)
=> database.ProviderName.Equals(
typeof(SqlServerOptionsExtension).GetTypeInfo().Assembly.GetName().Name,
StringComparison.Ordinal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Utilities;

// ReSharper disable once CheckNamespace
Expand Down
35 changes: 35 additions & 0 deletions src/EFCore.Sqlite.Core/SqliteDatabaseFacadeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;

namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// SQLite specific extension methods for <see cref="DbContext.Database" />.
/// </summary>
public static class SqliteDatabaseFacadeExtensions
{
/// <summary>
/// <para>
/// Returns true if the database provider currently in use is the SQLite provider.
/// </para>
/// <para>
/// This method can only be used after the <see cref="DbContext" /> has been configured because
/// it is only then that the provider is known. This means that this method cannot be used
/// in <see cref="DbContext.OnConfiguring" /> because this is where application code sets the
/// provider to use as part of configuring the context.
/// </para>
/// </summary>
/// <param name="database"> The facade from <see cref="DbContext.Database" />. </param>
/// <returns> True if SQLite is being used; false otherwise. </returns>
public static bool IsSqlite([NotNull] this DatabaseFacade database)
=> database.ProviderName.Equals(
typeof(SqliteOptionsExtension).GetTypeInfo().Assembly.GetName().Name,
StringComparison.Ordinal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore
Expand Down
21 changes: 21 additions & 0 deletions src/EFCore/Infrastructure/DatabaseFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand Down Expand Up @@ -182,6 +184,25 @@ public virtual IDbContextTransaction CurrentTransaction
/// </summary>
public virtual bool AutoTransactionsEnabled { get; set; } = true;

/// <summary>
/// <para>
/// Returns the invariant name of the database provider currently in use.
/// The invariant name is typically the name of the provider assembly.
/// It is usually easier to use a sugar method auch as 'IsSqlServer()' instead of
/// calling this method directly.
/// </para>
/// <para>
/// This method can only be used after the <see cref="DbContext" /> has been configured because
/// it is only then that the provider is known. This means that this method cannot be used
/// in <see cref="DbContext.OnConfiguring" /> because this is where application code sets the
/// provider to use as part of configuring the context.
/// </para>
/// </summary>
public virtual string ProviderName
=> _context.GetService<IEnumerable<IDatabaseProvider>>()
?.Select(p => p.InvariantName)
.FirstOrDefault();

/// <summary>
/// <para>
/// Gets the scoped <see cref="IServiceProvider" /> being used to resolve services.
Expand Down
25 changes: 25 additions & 0 deletions test/EFCore.InMemory.Tests/InMemoryDatabaseFacadeTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Xunit;

namespace Microsoft.EntityFrameworkCore.InMemory.Tests
{
public class InMemoryDatabaseFacadeTest
{
[Fact]
public void IsInMemory_when_using_in_memory()
{
using (var context = new ProviderContext())
{
Assert.True(InMemoryDatabaseFacadeExtensions.IsInMemory(context.Database));
}
}

private class ProviderContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseInMemoryDatabase("Maltesers");
}
}
}
185 changes: 185 additions & 0 deletions test/EFCore.SqlServer.Tests/SqlServerDatabaseFacadeTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.EntityFrameworkCore.Internal;
using Xunit;

namespace Microsoft.EntityFrameworkCore.SqlServer.Tests
{
public class SqlServerDatabaseFacadeTest
{
[Fact]
public void IsSqlServer_when_using_OnConfguring()
{
using (var context = new SqlServerOnConfiguringContext())
{
Assert.True(context.Database.IsSqlServer());
}
}

[Fact]
public void IsSqlServer_in_OnModelCreating_when_using_OnConfguring()
{
using (var context = new SqlServerOnModelContext())
{
var _ = context.Model; // Trigger context initialization
Assert.True(context.IsSqlServerSet);
}
}

[Fact]
public void IsSqlServer_in_constructor_when_using_OnConfguring()
{
using (var context = new SqlServerConstructorContext())
{
var _ = context.Model; // Trigger context initialization
Assert.True(context.IsSqlServerSet);
}
}

[Fact]
public void Cannot_use_IsSqlServer_in_OnConfguring()
{
using (var context = new SqlServerUseInOnConfiguringContext())
{
Assert.Equal(
CoreStrings.RecursiveOnConfiguring,
Assert.Throws<InvalidOperationException>(
() =>
{
var _ = context.Model; // Trigger context initialization
}).Message);
}
}

[Fact]
public void IsSqlServer_when_using_constructor()
{
using (var context = new ProviderContext(
new DbContextOptionsBuilder().UseSqlServer("Database=Maltesers").Options))
{
Assert.True(context.Database.IsSqlServer());
}
}

[Fact]
public void IsSqlServer_in_OnModelCreating_when_using_constructor()
{
using (var context = new ProviderOnModelContext(
new DbContextOptionsBuilder().UseSqlServer("Database=Maltesers").Options))
{
var _ = context.Model; // Trigger context initialization
Assert.True(context.IsSqlServerSet);
}
}

[Fact]
public void IsSqlServer_in_constructor_when_using_constructor()
{
using (var context = new ProviderConstructorContext(
new DbContextOptionsBuilder().UseSqlServer("Database=Maltesers").Options))
{
var _ = context.Model; // Trigger context initialization
Assert.True(context.IsSqlServerSet);
}
}

[Fact]
public void Cannot_use_IsSqlServer_in_OnConfguring_with_constructor()
{
using (var context = new ProviderUseInOnConfiguringContext(
new DbContextOptionsBuilder().UseSqlServer("Database=Maltesers").Options))
{
Assert.Equal(
CoreStrings.RecursiveOnConfiguring,
Assert.Throws<InvalidOperationException>(
() =>
{
var _ = context.Model; // Trigger context initialization
}).Message);
}
}

[Fact]
public void Not_IsSqlServer_when_using_different_provider()
{
using (var context = new ProviderContext(
new DbContextOptionsBuilder().UseInMemoryDatabase("Maltesers").Options))
{
Assert.False(context.Database.IsSqlServer());
}
}

private class ProviderContext : DbContext
{
protected ProviderContext()
{
}

public ProviderContext(DbContextOptions options)
: base(options)
{
}

public bool? IsSqlServerSet { get; protected set; }
}

private class SqlServerOnConfiguringContext : ProviderContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer("Database=Maltesers");
}

private class SqlServerOnModelContext : SqlServerOnConfiguringContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> IsSqlServerSet = Database.IsSqlServer();
}

private class SqlServerConstructorContext : SqlServerOnConfiguringContext
{
public SqlServerConstructorContext()
=> IsSqlServerSet = Database.IsSqlServer();
}

private class SqlServerUseInOnConfiguringContext : SqlServerOnConfiguringContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);

IsSqlServerSet = Database.IsSqlServer();
}
}

private class ProviderOnModelContext : ProviderContext
{
public ProviderOnModelContext(DbContextOptions options)
: base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
=> IsSqlServerSet = Database.IsSqlServer();
}

private class ProviderConstructorContext : ProviderContext
{
public ProviderConstructorContext(DbContextOptions options)
: base(options)
=> IsSqlServerSet = Database.IsSqlServer();
}

private class ProviderUseInOnConfiguringContext : ProviderContext
{
public ProviderUseInOnConfiguringContext(DbContextOptions options)
: base(options)
{
}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> IsSqlServerSet = Database.IsSqlServer();
}
}
}
Loading

0 comments on commit b9cd36d

Please sign in to comment.