#csharp #dotnet #backend

Day 19: CRUD Operations Part 2 (Update & Delete)

Welcome to Day 19. Today we finish the CRUD cycle by learning how to Update (PUT) and Delete (DELETE) records using EF Core.

Update (Modifying Data)

Updating data in EF Core is deeply integrated with its Change Tracker.

When you pull a record out of the database, EF Core “watches” it. If you change a property on that object, EF Core knows it was modified. When you call SaveChangesAsync(), EF Core generates a highly optimized UPDATE SQL statement for only the columns that changed.

app.MapPut("/books/{id}", async (int id, Book updatedBook, AppDbContext db) => 
{
    // 1. Fetch the existing entity from the database
    var existingBook = await db.Books.FindAsync(id);
    
    if (existingBook is null) return Results.NotFound();
    
    // 2. Modify the tracked entity
    existingBook.Title = updatedBook.Title;
    existingBook.Price = updatedBook.Price;
    existingBook.Author = updatedBook.Author;
    
    // 3. Save changes. EF Core fires an UPDATE behind the scenes!
    await db.SaveChangesAsync();
    
    return Results.NoContent(); // 204 typically means the update succeeded.
});

A note on Update vs ExecuteUpdateAsync

In .NET 7+, Microsoft introduced a blazing fast way to update multiple rows without having to fetch them from the database first:

// Give a 10% discount to ALL books written by "Stephen King"
await db.Books
    .Where(b => b.Author == "Stephen King")
    .ExecuteUpdateAsync(s => s.SetProperty(b => b.Price, b => b.Price * 0.90m));

This skips the Change Tracker entirely and issues a direct UPDATE Books SET Price = Price * 0.90 WHERE Author = 'Stephen King' to the database.

Delete (Removing Data)

Deleting involves fetching the entity, passing it to the Remove() method, and saving stringing.

app.MapDelete("/books/{id}", async (int id, AppDbContext db) => 
{
    // Fetch it
    var book = await db.Books.FindAsync(id);
    
    if (book is null) return Results.NotFound();
    
    // Flag it for deletion
    db.Books.Remove(book);
    
    // Execute the DELETE query
    await db.SaveChangesAsync();
    
    return Results.NoContent(); 
});

(Similarly, .NET 7 introduced ExecuteDeleteAsync() for massive bulk deletes without fetching properties!)

Challenge for Day 19

Implement a DELETE /books/expensive endpoint that uses .Where(b => b.Price > 100).ExecuteDeleteAsync() to wipe out all books over $100!

Tomorrow: Relational Data and Foreign Keys!