Skip to content

Consider adding AddInMemoryDatabase sugar #25487

@ajcvickers

Description

@ajcvickers

Split off from #25451.

Pros: Might be helpful when getting started.
Cons: Use of in-memory database is discouraged--see #18457

Implementation:

        /// <summary>
        ///     <para>
        ///         Registers the given Entity Framework <see cref="DbContext" /> as a service in the <see cref="IServiceCollection" />
        ///         and configures it to use the Entity Framework in-memory database.
        ///     </para>
        ///     <para>
        ///         This method is a shortcut for configuring a <see cref="DbContext" /> to use the in-memory database. It does not support
        ///         all options. Use <see cref="M:EntityFrameworkServiceCollectionExtensions.AddDbContext"/> and related methods for full
        ///         control of this process.
        ///     </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 in-memory database provider.
        ///     </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="databaseName">
        ///     The name of the in-memory database. This allows the scope of the in-memory database to be controlled
        ///     independently of the context. The in-memory database is shared anywhere the same name is used.
        /// </param>
        /// <param name="inMemoryOptionsAction"> An optional action to allow additional in-memory database 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 AddInMemoryDatabase<TContext>(
            this IServiceCollection serviceCollection,
            string databaseName,
            Action<InMemoryDbContextOptionsBuilder>? inMemoryOptionsAction = null,
            Action<DbContextOptionsBuilder>? optionsAction = null)
            where TContext : DbContext
        {
            Check.NotNull(serviceCollection, nameof(serviceCollection));
            Check.NotEmpty(databaseName, nameof(databaseName));

            return serviceCollection.AddDbContext<TContext>(
                (serviceProvider, options) =>
                {
                    optionsAction?.Invoke(options);
                    options.UseInMemoryDatabase(databaseName, inMemoryOptionsAction);
                });
        }

Test:

using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.InMemory.Infrastructure.Internal;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Microsoft.EntityFrameworkCore
{
    public class InMemoryDbContextOptionsBuilderExtensionsTest
    {
        [ConditionalFact]
        public void Service_collection_extension_method_can_configure_InMemory_options()
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddInMemoryDatabase<ApplicationDbContext>(
                "Crunchie",
                inMemoryOptions =>
                {
                    inMemoryOptions.EnableNullabilityCheck(false);
                },
                dbContextOption =>
                {
                    dbContextOption.EnableDetailedErrors();
                });

            var services = serviceCollection.BuildServiceProvider(validateScopes: true);

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

                Assert.True(coreOptions.DetailedErrorsEnabled);

                var inMemoryOptions = serviceScope.ServiceProvider
                    .GetRequiredService<DbContextOptions<ApplicationDbContext>>().GetExtension<InMemoryOptionsExtension>();

                Assert.False(inMemoryOptions.IsNullabilityCheckEnabled);
                Assert.Equal("Crunchie", inMemoryOptions.StoreName);
            }
        }

        private class ApplicationDbContext : DbContext
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                : base(options)
            {
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions