C# EntityFramework InMemory Database for Easy Testing/Prototyping and Project sharing.

We’ve all been there: create a new project for a client, create a database in some form, share the project and include some instructions on how to create the database for the project.

They get the project, it builds — which is great! — but then it comes down to constructing the database. They may not have an instance of the database system you used (MSSQL, MYSQL, MongoDB, etc), which means they won’t be able to run the project.

Fortunately for us and for them, this isn’t the end of the world; there are ways we can get around this issue.

Let’s take advantage of the EntityFramework InMemory feature. I’ve created a Razor Page .NET 5 project and installed the following NuGet packages:

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.InMemory

Once these are installed, we can create a very basic database structure. Let’s first create the two tables we want to store:

Database/Tables/Movie.cs

namespace EFInMemoryDatabase.Database.Tables
{
public class Movie
{
public int MovieId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int GenreId { get; set; }
}
}

Database/Tables/Genre.cs (this isn’t used, it’s just for demonstration)

namespace EFInMemoryDatabase.Database.Tables
{
public class Genre
{
public int GenreId { get; set; }
public string Label { get; set; }
}
}

We now need to create the actual “database”. We will create two DbSets, one for Movie and one for Genre. The DbSet class represents an entity set that can be used for the database operation, such as create, read, update, and delete (https://entityframework.net/ef-dbset).

Database/MovieContext.cs

using EFInMemoryDatabase.Database.Tables;
using Microsoft.EntityFrameworkCore;
namespace EFInMemoryDatabase.Database
{
public class MovieContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
public DbSet<Genre> Genres { get; set; }
public MovieContext(DbContextOptions options) : base(options)
{
LoadMovies();
LoadGenres();
SaveChanges();
}
public void LoadMovies()
{
Movies.Add(new Movie()
{
Description = "An organized crime dynasty's aging patriarch transfers control of his clandestine empire to his reluctant son.",
GenreId = 1,
MovieId = 1,
Title = "The Godfather"
});
Movies.Add(new Movie()
{
Description = "Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.",
GenreId = 2,
MovieId = 2,
Title = "The Shawshank Redemption"
});
Movies.Add(new Movie()
{
Description = "In German-occupied Poland during World War II, industrialist Oskar Schindler gradually becomes concerned for his Jewish workforce after witnessing their persecution by the Nazis.",
GenreId = 2,
MovieId = 3,
Title = "Schindler's List "
});
}
public void LoadGenres()
{
Genres.Add(new Genre()
{
GenreId = 1,
Label = "Crime"
});
Genres.Add(new Genre()
{
GenreId = 2,
Label = "Drama"
});
}
}
}

Now let’s update our Startup.cs so we can setup DI (dependency injection) for our application. In our Startup.cs we will need to add a database context and use the “UseInMemoryDatabase” feature which comes from Microsoft.EntityFrameworkCore.InMemory NuGet package.

Startup.cs

...
public void ConfigureServices(IServiceCollection services)
{
// Add this single line into your ConfigureServices method
services.AddDbContext<MovieContext>(o => o.UseInMemoryDatabase(nameof(MovieContext)));
services.AddRazorPages();
}
...

Now let’s update our Index.cshtml code so we can gather our movies from the database and then display them on the page.

Pages/Index.cshtml

@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
@foreach (var x in Model.Movies)
{
<h1>@x.Title</h1>
<span>@x.Description</span>
<i>Genre: @x.GenreId</i>
}
</div>

Pages/Index.cshtml.cs

using EFInMemoryDatabase.Database;
using EFInMemoryDatabase.Database.Tables;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
namespace EFInMemoryDatabase.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly MovieContext _context;
public List<Movie> Movies { get; set; }
public IndexModel(
ILogger<IndexModel> logger,
MovieContext context)
{
_logger = logger;
_context = context;
}
public void OnGet()
{
Movies = _context.Movies.ToList();
}
}
}

And that’s about it! Now anyone you give this project to will be able to run it without a problem.

The database self populates on construction and is stored in memory. This does mean any changes you do in the web app I.E. add a new movie will be lost when you stop the application (add movie to database feature not implemented). But remember the InMemory feature is made for testing/prototyping.

If you just want to see the code in action you can download my code from GitHub here (you will need .NET 5 SDK installed): https://github.com/MrApproved/Medium_EFInMemoryDatabase

Thank you for reading, I hope this has helped you or has taught you something new. Feel free to provide feedback, positive or negative.

References:
https://www.entityframeworktutorial.net/what-is-entityframework.aspx
https://entityframeworkcore.com/providers-inmemory

Repository: https://github.com/MrApproved/Medium_EFInMemoryDatabase
Image: https://www.pexels.com/photo/green-typewriter-with-white-typewriter-4065406/

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store