ASP.NET Core 2.2 - In Memory Entities
This article will demonstrate the creation of a small in-memory database which I will use in upcoming articles about table functions. I will assume you have created a new ASP.NET Core 2.2 Razor Pages project. I won't use Identity or Individual User Accounts.
This article starts a series about table functions:
The FREE ASP.NET Core 6.0 - Demos And Utilities Project includes a Table Functions Demo. Access to the source code is free for registered users at Manage > Assets.
To describe table functions, I wanted a simple set of entities with a few different property types. I started my research with the article Using EF Core's InMemory Provider To Store A "Database" In Memory by Matthew Jones. I wanted more records with fields which could be filtered and sorted. I used lists of fruit, vegetable and spice names from Fruits and Vegetables: List, Names & Pictures to help create the entities. Using an in-memory database allowed quick data modification for testing purposes.
Let's start with the entity class. I will use an enum for FoodType. Create a new root folder named Entities.
Add a new class named Food to the Entities folder:
public enum FoodType { All, Fruit, Vegtable, Other } public class Food { [Key] public int Id { get; set; } public string Name { get; set; } public FoodType FoodType { get; set; } public bool ColdStore { get; set; } public DateTime Date { get; set; } }
We need a DbContext for injection. Create a new root folder named Data.
Add a new class named FoodDbContext to the Data folder:
public class FoodDbContext : DbContext { public FoodDbContext(DbContextOptionsoptions) : base(options) { } public DbSet<Food> Foods { get; set; } }
Employ the UseInMemoryDatabase option when adding the DbContext to services.
Edit Startup.cs > ConfigureServices, add the DbContext:
services.AddDbContext<FoodDbContext>(options => options.UseInMemoryDatabase(databaseName: "Foods"));
I like Matthew Jones' DataGenerator approach which creates the database at application start. Create a new root folder named Services.
Add a new class named DataGenerator to the Services folder:
public class DataGenerator { public static void Initialize(IServiceProvider serviceProvider) { using (var context = new FoodDbContext( serviceProvider.GetRequiredService<DbContextOptions<FoodDbContext>>())) { // Look for any foods. if (context.Foods.Any()) { return; // Data was already seeded } int i = 0, id = 0, coldStoreFactor = 3; DateTime baseTime = DateTime.Now; var fruits = @"Apple,Watermelon,Orange,Pear,Cherry,Strawberry,Nectarine, Grape,Mango,Blueberry,Pomegranate,Starfruit,Plum,Banana,Raspberry,Mandarin,Jackfruit, Papaya,Kiwi,Pineapple,Lime,Lemon,Apricot,Grapefruit,Melon,Coconut,Avocado,Peach"; var fruitList = fruits.Split(',').ToList(); foreach (string fruit in fruitList) { i++; id++; context.Foods.Add(new Food() { Id = id, Name = fruit.Trim(), FoodType = FoodType.Fruit, ColdStore = i % coldStoreFactor == 0, Date = baseTime.AddHours(i).AddMinutes(id) }); context.SaveChanges(); }; i = 0; var vegtables = @"Corn,Mushroom,Broccoli,Cucumber,Red bell pepper, Tomato,Rutabaga,Carrot,Brussels sprout,Pumpkin,Cabbage,Potato,Eggplant, Sweet potato,Turnip,Zucchini,Green chilli,Onion,Lettuce,Radish,Pea,Asparagus,Celery, Green pepper,French beans,Spinach,Beet,Red chili peppers,Bean"; var vegtableList = vegtables.Split(',').ToList(); foreach (string vegtable in vegtableList) { i++; id++; context.Foods.Add(new Food() { Id = id, Name = vegtable.Trim(), FoodType = FoodType.Vegtable, ColdStore = i % coldStoreFactor == 0, Date = baseTime.AddHours(i).AddMinutes(id) }); context.SaveChanges(); }; i = 0; var spices = @"Cilantro,Artichoke,Rosemary,Bay leaves,Mint leaves,Basil,Clove, Olive,Shallot,Turmeric,Garlic,Ginger,Onion,Green onions,Lemongrass,Chives,Green chili"; var spiceList = spices.Split(',').ToList(); foreach (string spice in spiceList) { i++; id++; context.Foods.Add(new Food() { Id = id, Name = spice.Trim(), FoodType = FoodType.Other, ColdStore = i % coldStoreFactor == 0, Date = baseTime.AddHours(i).AddMinutes(id) }); context.SaveChanges(); }; } } }
Call the DataGenerator > Initialize method after the build and before the run commands for CreateWebHostBuilder.
Edit Program.cs > Main:
//CreateWebHostBuilder(args).Build().Run(); //1. Get the IWebHost which will host this application. var host = CreateWebHostBuilder(args).Build(); //2. Find the service layer within our scope. using (var scope = host.Services.CreateScope()) { //3. Get the instance of FoodDbContext in our services layer var services = scope.ServiceProvider; var context = services.GetRequiredService<FoodDbContext>(); //4. Call the DataGenerator to create sample data DataGenerator.Initialize(services); } //Continue to run the application host.Run();
Resolve any namespace issues.
Access the Food entities from any page using dependency injection.
Edit Index.cs > IndexModel:
private readonly FoodDbContext _context; public DataModel(FoodDbContext context) { _context = context; } public IList<Food> Foods { get; set; } = new List<Food>(); public void OnGet() { Foods = _context.Foods.ToList(); }
Edit Index.cshtml, add the table:
<div class="row"> <div class="col-12"> <table class="table"> <thead> <tr> <th> @Html.DisplayNameFor(model => model.Foods[0].Id) </th> <th> @Html.DisplayNameFor(model => model.Foods[0].Name) </th> <th> @Html.DisplayNameFor(model => model.Foods[0].FoodType) </th> <th> @Html.DisplayNameFor(model => model.Foods[0].ColdStore) </th> <th> @Html.DisplayNameFor(model => model.Foods[0].Date) </th> </tr> </thead> <tbody> @if (Model.Foods.Count > 0) { foreach (var item in Model.Foods) { <tr> <td> @Html.DisplayFor(modelItem => item.Id) </td> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.DisplayFor(modelItem => item.FoodType) </td> <td> <input type="checkbox" asp-for="@item.ColdStore"> </td> <td> @Html.DisplayFor(modelItem => item.Date) </td> </tr> } } else { <tr> <td colspan="5" class="text-center"> No Food Found </td> </tr> } </tbody> </table> </div> </div>
Build, run and test.
Update 12/30/2021
Announced the ASP.NET Core 6.0 - Demos And Utilities Project. Updated articles, asset and topic links.
Comments(0)