Tutorial: Using Entity Framework Core as an In-Memory Database for ASP.NET Core

Datetime:2016-08-22 22:09:27          Topic: DataBase  ASP.NET           Share

One of the most exciting features in the new version of Entity Framework (Entity Framework Core 1.0) is the addition of an in-memory data provider. This makes it possible to prototype applications and write tests without having to set up a local or external database. When you’re ready to switch to using a real database, you can simply swap in your actual provider.

In this tutorial, I’ll show you how to set up the Entity Framework Core InMemory provider and use it to prototype a simple ASP.NET Core API. If you’ve never set up ASP.NET Core before, follow my earlier tutorial on creating a new ASP.NET Core project to create a new API application called PrototypeApi .

Setting up Entity Framework Core

First, add the Microsoft.EntityFrameworkCore.InMemory package to your project. In Visual Studio, you can use the NuGet Package Manager to do this (right-click on the project and choose Manage NuGet Packages). Alternatively, you can edit the project.json file and add this line to the dependencies section:

"Microsoft.EntityFrameworkCore.InMemory": "1.0.0"

Use dotnet restore to install the package if you aren’t using Visual Studio.

The API I’ll be demonstrating contains a collection of users and a collection of posts. Create some model classes to represent these entities (in a new folder called DbModels):

DbModels/User.cs

usingSystem.Collections.Generic;
 
namespace PrototypeApi.DbModels
{
    public class User
    {
        public string Id { get; set; }
 
        public string FirstName { get; set; }
 
        public string LastName { get; set; }
 
        public List<Post> Posts { get; set; }
    }
}

DbModels/Post.cs

usingSystem;
 
namespace PrototypeApi.DbModels
{
    public class Post
    {
        public string Id { get; set; }
 
        public string UserId { get; set; }
 
        public User User { get; set; }
 
        public string Content { get; set; }
    }
}

These simple classes will represent the data that will be saved and loaded from the database.

In this data model, there’s a straightforward one-to-many relationship between Users and Posts: a Post is “owned” by a User, and a User may have many Posts. The Posts and User properties will be automatically discovered and populated by Entity Framework Core.

You’ll also need to create a DbContext that represents the connection to the database:

ApiContext.cs

usingMicrosoft.EntityFrameworkCore;
usingPrototypeApi.DbModels;
 
namespace PrototypeApi
{
    public class ApiContext : DbContext
    {
        public ApiContext(DbContextOptions<ApiContext> options)
            : base(options)
        {
        }
 
        public DbSet<User> Users { get; set; }
 
        public DbSet<Post> Posts { get; set; }
    }
}

You’re all set to connect this database context to your application using the in-memory data provider. In your Startup class’ ConfigureServices method, add a new line:

public void ConfigureServices(IServiceCollectionservices)
{
    services.AddDbContext<ApiContext>(opt => opt.UseInMemoryDatabase());
 
    services.AddMvc();
}

At the top of the Startup class, add this line:

usingMicrosoft.EntityFrameworkCore;

Seeding With Test Data on Startup

To add data to the in-memory database when the application starts up, add some code to the Configure method:

public void Configure(IApplicationBuilderapp, IHostingEnvironmentenv, ILoggerFactoryloggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();
 
    var context = app.ApplicationServices.GetService<ApiContext>();
    AddTestData(context);
 
    app.UseMvc();
}

The new AddTestData method looks like this:

private static void AddTestData(ApiContextcontext)
{
    var testUser1 = new DbModels.User
    {
        Id = "abc123",
        FirstName = "Luke",
        LastName = "Skywalker"
    };
 
    context.Users.Add(testUser1);
 
    var testPost1 = new DbModels.Post
    {
        Id = "def234",
        UserId = testUser1.Id,
        Content = "What a piece of junk!"
    };
 
    context.Posts.Add(testPost1);
 
    context.SaveChanges();
}

Retrieving the Data

Querying and retrieving data from an in-memory provider use the same methods as any Entity Framework Core provider. To demonstrate retrieving the Users and Posts stored in the prototype database, create a simple controller:

Controllers/UsersController.cs

usingSystem.Linq;
usingSystem.Threading.Tasks;
usingMicrosoft.AspNetCore.Mvc;
usingMicrosoft.EntityFrameworkCore;
 
namespace PrototypeApi.Controllers
{
    [Route("api/[controller]")]
    public class UsersController : Controller
    {
        private readonlyApiContext_context;
 
        public UsersController(ApiContextcontext)
        {
            _context = context;
        }
 
        public asyncTask<IActionResult> Get()
        {
            var users = await_context.Users
                .Include(u => u.Posts)
                .ToArrayAsync();
 
            var response = users.Select(u => new
            {
                firstName = u.FirstName,
                lastName = u.LastName,
                posts = u.Posts.Select(p => p.Content)
            });
 
            return Ok(response);
        }
    }
}

This does two things: it requests an ApiContext object from the dependency injection service (using constructor injection) and exposes an HTTP GET route that returns all the users (and their posts) currently stored in the database.

In the Get method, the Include method explicitly tells Entity Framework Core to load the User’s Posts along with their other details. Entity Framework Core is smart enough to understand that the UserId field on the Post model represents a foreign key relationship between Users and Posts.

After the users and posts are asynchronously retrieved from the database, the array is projected (using Select ) into a response model that includes only the fields you need in the response. This keeps the JSON response minimal.

Next Steps

I’ve used the InMemory provider to rapidly prototype APIs and test ideas, and my favorite part is the ability to switch one line of code ( AddDbContext in the Startup class) to connect to a live database like SQL Server.

This isn’t the only application of the InMemory provider, though. It’s also useful for building integration tests that need to exercise your data access layer or data-related business code. Instead of standing up a database for testing, you can run these integration tests entirely in memory.

Check out these resources to learn more about testing with InMemory, and ASP.NET Core:

  • Testing With InMemory
  • EF Core vs. EF6.x comparison
  • Set up ASP.NET Core on Windows, Mac, and Linux
  • Deploy an ASP.NET Core Application on Linux with Docker
  • If you have questions about using an in-memory database with Entity Framework Core, hit me up on Twitter @nbarbattini or leave a comment below!





    About List