Documentation Index
Fetch the complete documentation index at: https://mintlify.com/aws-samples/legacy-cycle-store-mvc-app/llms.txt
Use this file to discover all available pages before exploring further.
The most structurally significant change in the Cycle Store migration is replacing the Entity Framework 5 Database-First EDMX model with EF Core Code-First. In EF5, the database schema is the source of truth: Visual Studio reads the database and generates a .edmx XML file, .tt T4 templates, and auto-generated partial C# classes from those templates. EF Core has no EDMX concept — entity classes are plain C# POCOs and the DbContext is configured in code. This page walks through every concrete change required in the data-access layer.
Current EF5 Pattern
The legacy application’s data context lives in the AdventureWorks.Business namespace. The generated CYCLE_STOREEntities class inherits from DbContext using a named connection string and includes a guard method that prevents accidental Code-First use:
// Auto-generated by the EDMX T4 template — do not edit by hand
namespace AdventureWorks.Business
{
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class CYCLE_STOREEntities : DbContext
{
public CYCLE_STOREEntities()
: base("name=CYCLE_STOREEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Intentionally throws — this context was generated from an EDMX
// and must not be used with Code-First conventions.
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<ProductCategory> ProductCategories { get; set; }
public virtual DbSet<ProductSubcategory> ProductSubcategories { get; set; }
}
}
The connection string that powers this context lives in Web.config and contains Entity Framework metadata references that point to the embedded EDMX resources:
<connectionStrings>
<add name="CYCLE_STOREEntities"
connectionString="metadata=res://*/CycleModel.csdl|res://*/CycleModel.ssdl|res://*/CycleModel.msl;
provider=System.Data.SqlClient;
provider connection string="data source=<rds-endpoint>;
initial catalog=CYCLE_STORE;user id=DBUser;password=<password>;
MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
This EF5 metadata connection string format is entirely specific to the EDMX pipeline. EF Core does not understand it.
The OnModelCreating override that throws UnintentionalCodeFirstException is an EF5 safety guard injected by the T4 template. It must be removed when writing the EF Core DbContext. In EF Core, OnModelCreating is the correct place to configure the model — throwing an exception there would break every database operation.
EF Core Package
Remove the EntityFramework 5.0.0 NuGet package and replace it with the EF Core SQL Server provider. In the SDK-style .csproj used by ASP.NET Core projects, packages are declared as <PackageReference> items rather than entries in a separate packages.config file:
<!-- Remove this (legacy packages.config entry) -->
<!-- <package id="EntityFramework" version="5.0.0" targetFramework="net45" /> -->
<!-- Add this inside an <ItemGroup> in the .csproj -->
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.32" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.32">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
Microsoft.EntityFrameworkCore.SqlServer pulls in the core EF Core runtime as a transitive dependency. The Design package is required only at build time for tooling such as dotnet ef migrations.
New DbContext
Replace CYCLE_STOREEntities with a new CycleStoreContext class in a dedicated AdventureWorks.Data namespace. The EF Core DbContext accepts options through its constructor — this is what enables dependency injection and makes the context testable:
using Microsoft.EntityFrameworkCore;
using AdventureWorks.Business;
namespace AdventureWorks.Data
{
public class CycleStoreContext : DbContext
{
public CycleStoreContext(DbContextOptions<CycleStoreContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
public DbSet<ProductCategory> ProductCategories { get; set; }
public DbSet<ProductSubcategory> ProductSubcategories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// The AdventureWorks CYCLE_STORE tables live in the Production schema.
// EF Core defaults to dbo — override with the correct schema here.
modelBuilder.HasDefaultSchema("Production");
}
}
}
Key differences from the EF5 version:
- The constructor takes
DbContextOptions<CycleStoreContext> instead of a hard-coded connection string name.
OnModelCreating receives a ModelBuilder (EF Core) rather than a DbModelBuilder (EF5) — these are different types with different APIs.
- The
virtual modifier on DbSet properties is no longer needed (EF Core does not use lazy-loading proxies by default).
- There is no
UnintentionalCodeFirstException — Code-First is the only EF Core approach.
Entity Classes
In the EF5 EDMX workflow, T4 templates generate partial C# classes for every entity in the model. These files are regenerated from the .edmx each time the database schema changes, which means they cannot be hand-edited safely. In EF Core, entity classes are plain C# POCO classes that you author and maintain directly.
The good news is that the property signatures stay the same — only the generation mechanism changes. A Product entity that was previously generated might look like this:
// EF5 auto-generated partial class (from CycleModel.tt)
namespace AdventureWorks.Business
{
public partial class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string ProductNumber { get; set; }
public string Color { get; set; }
public decimal StandardCost { get; set; }
public decimal ListPrice { get; set; }
public string Size { get; set; }
public decimal? Weight { get; set; }
public string Description { get; set; }
public int ProductSubcategoryID { get; set; }
public virtual ProductSubcategory ProductSubcategory { get; set; }
}
}
In EF Core, you write the same class directly — no T4 template, no partial keyword required:
// EF Core POCO entity class — hand-authored, owned by the team
namespace AdventureWorks.Business
{
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string ProductNumber { get; set; }
public string Color { get; set; }
public decimal StandardCost { get; set; }
public decimal ListPrice { get; set; }
public string Size { get; set; }
public decimal? Weight { get; set; }
public string Description { get; set; }
public int ProductSubcategoryID { get; set; }
public ProductSubcategory ProductSubcategory { get; set; }
}
}
The EDMX files (CycleModel.edmx, CycleModel.Context.tt, CycleModel.tt, and all .cs files they generate) are removed entirely from the project. EF Core has no concept of an EDMX and will not read or generate one. Delete these files before adding the new Code-First classes to avoid compilation conflicts.
Connection String
Replace the EF5 metadata connection string in Web.config with a plain SQL Server connection string in appsettings.json. EF Core’s SQL Server provider accepts a standard ADO.NET connection string — there are no metadata resource references:
{
"ConnectionStrings": {
"CycleStore": "Server=<rds-endpoint>;Database=CYCLE_STORE;User Id=DBUser;Password=<password>;MultipleActiveResultSets=True;"
}
}
The key name (CycleStore) is arbitrary — it must match the name used when reading the connection string in Startup.cs. For container deployments, this value is overridden at runtime via an environment variable (see Containerization).
Dependency Injection
Register CycleStoreContext with the ASP.NET Core built-in DI container in Startup.cs. The AddDbContext extension method reads the connection string from IConfiguration and configures the SQL Server provider:
// Startup.cs — ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CycleStoreContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("CycleStore")));
services.AddControllersWithViews();
}
Once registered, CycleStoreContext can be injected into any service or controller via constructor injection. The DI container manages the context lifetime (scoped per HTTP request by default), which is the correct behaviour for a web application.
Update the Business Layer
The legacy CategoryManager and ProductManager classes in AdventureWorks.Business instantiate CYCLE_STOREEntities directly using a using block:
// Legacy pattern — direct static instantiation inside each method
public List<ProductCategory> GetMainCategories()
{
using (var db = new CYCLE_STOREEntities())
{
return db.ProductCategories.ToList();
}
}
In the modernized application, the managers receive CycleStoreContext through constructor dependency injection. The DI container provides the same scoped instance across the entire HTTP request:
// Modernized pattern — context injected via constructor
public class CategoryManager
{
private readonly CycleStoreContext _db;
public CategoryManager(CycleStoreContext db)
{
_db = db;
}
public List<ProductCategory> GetMainCategories()
{
return _db.ProductCategories.ToList();
}
public ProductCategory GetCategoryByName(string name)
{
return _db.ProductCategories
.FirstOrDefault(c => c.Name == name);
}
public ProductSubcategory GetProductSubcategoryByName(string name)
{
return _db.ProductSubcategories
.FirstOrDefault(s => s.Name == name);
}
}
Register both managers in Startup.ConfigureServices so they too can be injected into controllers:
services.AddScoped<CategoryManager>();
services.AddScoped<ProductManager>();
The LINQ query bodies inside each method (GetProductByName, GetProductByCategory, GetProductByProductId, GetProductColor, GetProductWeight, GetProductSize, GetProductDesc) need no changes — EF Core translates the same LINQ expressions to SQL as EF5 did.