ASP.NET Core  

How ASP.NET Core MVC Performs CRUD Without SQL Queries | Beginner-Friendly EF Core

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# ClassSQL Table
EmployeeEmployees
EmployeeIdPrimary Key column
Namenvarchar column
Departmentnvarchar 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:

  • DbContext = database connection

  • DbSet<Employee> = Employees table

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:

ModelTable
ProductProducts
EmployeeEmployees
UserUsers

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