Below is a complete, ready-to-publish blog article explaining How CRUD works in ASP.NET Core MVC Without Writing SQL Queries and How EF Core Knows the Table Name — written in simple, beginner-friendly language.
If you are coming from ASP.NET WebForms, you are probably familiar with writing SQL queries like:
SELECT * FROM Employees
INSERT INTO Employees(...)
UPDATE Employees SET...
DELETE FROM Employees
But when you switch to ASP.NET Core MVC, you will notice something strange:
No SQL queries
No SqlConnection
No SqlCommand
No stored procedures
Still CRUD works perfectly
How?
This is because ASP.NET Core uses a powerful technology called Entity Framework Core (EF Core).
In this article, you will learn:
What EF Core is
How EF Core knows your table name
How CRUD works without SQL
What DbContext, DbSet, and Models are
How methods like Index(), Create(), Edit() actually work
Complete code with explanation
Let’s begin.
1. What Is Entity Framework Core?
Entity Framework Core (EF Core) is an ORM (Object Relational Mapper).
ORM means:
It converts C# classes into database tables
and C# LINQ operations into SQL queries.
So instead of manually writing SQL queries, you just write C# code.
EF Core generates SQL and executes it on the database automatically.
2. Your Model = Your Table
Example model:
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Department { get; set; }
}
EF Core automatically does this:
| C# Class | SQL Table |
|---|
| Employee | Employees |
| EmployeeId | Primary Key column |
| Name | nvarchar column |
| Department | nvarchar column |
You didn’t write SQL, but the table is created by EF using migrations.
3. DbContext = Your Database Connection
Your application contains a DbContext which maps tables.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
public DbSet<Employee> Employees { get; set; }
}
What this means:
EF Core now knows:
1.Table Name = Employees
2.Columns = properties of Employee class
4. Connection String in appsettings.json
"ConnectionStrings": {
"DefaultConnection": "Server=softsql;Database=SampleMVCCore;User Id=sa;Password=capmark@09;Connect Timeout=60;Max Pool Size=10000;TrustServerCertificate=True;"
}
This tells EF Core which database to use.
In Program.cs, EF Core is connected:
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
Now your controller can access your database using _context.
5. How SELECT Works Without SQL?
Controller code:
public async Task<IActionResult> Index()
{
var employees = await _context.Employees.ToListAsync();
return View(employees);
}
EF Core automatically generates SQL:
SELECT * FROM Employees;
6. How INSERT Works Without SQL?
POST method:
public async Task<IActionResult> Create(Employee employee)
{
if (ModelState.IsValid)
{
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
EF Core generates:
INSERT INTO Employees (Name, Department) VALUES ('John', 'IT');
7. How UPDATE Works Without SQL?
_context.Update(employee);
await _context.SaveChangesAsync();
EF Core generates:
UPDATE Employees SET ... WHERE EmployeeId = 1;
8. How DELETE Works Without SQL?
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
EF Core generates:
DELETE FROM Employees WHERE EmployeeId = 1;
9. Why Does EF Core Know the Table Name?
Because of:
1. Model class name → Employee
2. DbSet name → Employees
3. EF conventions add "s" → Employees
EF Core naming system automatically maps:
| Model | Table |
|---|
| Product | Products |
| Employee | Employees |
| User | Users |
10. What If You Want a Custom Table Name?
Use Fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().ToTable("Emp_Master");
}
Now EF Core uses:
SQL Table Name: Emp_Master
11. Explanation of IActionResult
What is IActionResult?
IActionResult is a return type in MVC that allows you to return:
View
JSON
Redirect
File
Status code
Anything
Example
public IActionResult Create()
{
return View();
}
This means → return a web page.
Why use IActionResult instead of string or void?
Because MVC needs flexibility.
Example:
if(success)
return RedirectToAction("Index");
else
return View(model);
12. Why async Task?
Because database operations are slow.
async / await improves performance by not blocking the thread.
Example
public async Task<IActionResult> Index()
{
var employees = await _context.Employees.ToListAsync();
return View(employees);
}
1. Non-blocking
2. Faster
3. Recommended for all DB operations
13. Full CRUD Example (Your Provided Code)
This is your controller — already perfect:
public class EmployeeController : Controller
{
private readonly ApplicationDbContext _context;
public EmployeeController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var employees = await _context.Employees.ToListAsync();
return View(employees);
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Employee employee)
{
if (ModelState.IsValid)
{
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
public async Task<IActionResult> Edit(int id)
{
var employee = await _context.Employees.FindAsync(id);
if (employee == null) return NotFound();
return View(employee);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Employee employee)
{
if (id != employee.EmployeeId) return NotFound();
if (ModelState.IsValid)
{
_context.Update(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
public async Task<IActionResult> Delete(int id)
{
var employee = await _context.Employees.FindAsync(id);
if (employee == null) return NotFound();
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
Conclusion
1.No SQL because EF Core auto-generates queries
2. DbContext + DbSet define your table
3. Model = table structure
4. SaveChangesAsync() runs SQL internally
5. IActionResult gives flexibility in return types
6.Async improves performance