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(DbContextOptions options)
: 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)