.Net Core
Asynch Database Operations

Give examples of Async database operations?

In ASP.NET Core, asynchronous database operations are crucial for improving application scalability and responsiveness, especially when dealing with I/O-bound tasks like querying a database. Asynchronous methods allow the server to handle multiple requests simultaneously without blocking the main thread while waiting for the database operation to complete.

When working with databases in ASP.NET Core, Entity Framework Core (EF Core) provides built-in asynchronous methods, such as ToListAsync(), FirstOrDefaultAsync(), FindAsync(), and SaveChangesAsync() to handle database operations efficiently.

1. Example: Async Get Operation (Retrieving Data)

In this example, we will retrieve a list of products from a database asynchronously.

Product Entity

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

DbContext

public class MyAppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
 
    public MyAppDbContext(DbContextOptions<MyAppDbContext> options) : base(options)
    {
    }
}

Async Method to Fetch Data

Here’s how you can asynchronously fetch a list of products from the database:

public class ProductService
{
    private readonly MyAppDbContext _context;
 
    public ProductService(MyAppDbContext context)
    {
        _context = context;
    }
 
    public async Task<List<Product>> GetProductsAsync()
    {
        // Asynchronous method to fetch all products
        return await _context.Products.ToListAsync();
    }
 
    public async Task<Product> GetProductByIdAsync(int id)
    {
        // Asynchronous method to fetch a product by ID
        return await _context.Products.FirstOrDefaultAsync(p => p.Id == id);
    }
}

Using the Asynchronous Methods in a Razor Page or Controller

In a Razor Page or Controller, you can use the ProductService to asynchronously fetch the data.

Example in Razor Page:

public class ProductsModel : PageModel
{
    private readonly ProductService _productService;
 
    public List<Product> Products { get; set; }
 
    public ProductsModel(ProductService productService)
    {
        _productService = productService;
    }
 
    public async Task OnGetAsync()
    {
        // Fetch the list of products asynchronously
        Products = await _productService.GetProductsAsync();
    }
}

2. Example: Async Save Operation (Inserting Data)

When inserting new data into the database, use the SaveChangesAsync() method to asynchronously save changes.

Async Method to Insert Data

public class ProductService
{
    private readonly MyAppDbContext _context;
 
    public ProductService(MyAppDbContext context)
    {
        _context = context;
    }
 
    public async Task AddProductAsync(Product product)
    {
        // Add the new product to the context
        await _context.Products.AddAsync(product);
        
        // Save the changes asynchronously
        await _context.SaveChangesAsync();
    }
}

Using the Async Save Method

In the Razor Page or Controller, you can call the AddProductAsync method to insert data asynchronously.

public class CreateProductModel : PageModel
{
    private readonly ProductService _productService;
 
    [BindProperty]
    public Product NewProduct { get; set; }
 
    public CreateProductModel(ProductService productService)
    {
        _productService = productService;
    }
 
    public void OnGet()
    {
        // Initialize the page
    }
 
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
 
        // Insert the new product asynchronously
        await _productService.AddProductAsync(NewProduct);
 
        return RedirectToPage("Products");
    }
}

3. Example: Async Update Operation

For updating existing data in the database, use asynchronous methods like SaveChangesAsync().

Async Method to Update Data

public class ProductService
{
    private readonly MyAppDbContext _context;
 
    public ProductService(MyAppDbContext context)
    {
        _context = context;
    }
 
    public async Task UpdateProductAsync(Product product)
    {
        // Update the product entity
        _context.Products.Update(product);
        
        // Save the changes asynchronously
        await _context.SaveChangesAsync();
    }
}

Using the Async Update Method

public class EditProductModel : PageModel
{
    private readonly ProductService _productService;
 
    [BindProperty]
    public Product Product { get; set; }
 
    public EditProductModel(ProductService productService)
    {
        _productService = productService;
    }
 
    public async Task OnGetAsync(int id)
    {
        // Fetch the product by ID asynchronously
        Product = await _productService.GetProductByIdAsync(id);
    }
 
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
 
        // Update the product asynchronously
        await _productService.UpdateProductAsync(Product);
 
        return RedirectToPage("Products");
    }
}

4. Example: Async Delete Operation

For deleting data from the database, you can use asynchronous methods as well.

Async Method to Delete Data

public class ProductService
{
    private readonly MyAppDbContext _context;
 
    public ProductService(MyAppDbContext context)
    {
        _context = context;
    }
 
    public async Task DeleteProductAsync(int id)
    {
        var product = await _context.Products.FindAsync(id);
        if (product != null)
        {
            _context.Products.Remove(product);
            await _context.SaveChangesAsync();
        }
    }
}

Using the Async Delete Method

public class DeleteProductModel : PageModel
{
    private readonly ProductService _productService;
 
    public DeleteProductModel(ProductService productService)
    {
        _productService = productService;
    }
 
    public async Task<IActionResult> OnPostDeleteAsync(int id)
    {
        // Delete the product asynchronously
        await _productService.DeleteProductAsync(id);
        return RedirectToPage("Products");
    }
}

5. Real-Life Analogy for Async Database Operations

Consider a customer ordering food in a restaurant. The waiter takes the order and hands it to the kitchen. While the customer’s meal is being prepared, the waiter doesn't stand idle; instead, they attend to other customers. Once the meal is ready, they serve it to the customer. This approach is similar to how asynchronous operations work: instead of waiting for one task to complete, the application can handle other tasks (or requests), improving overall efficiency.

6. Key Points for Asynchronous Database Operations

  • ToListAsync(), FirstOrDefaultAsync(), FindAsync(): Asynchronous methods for querying data.
  • AddAsync(), SaveChangesAsync(): Asynchronous methods for inserting and saving changes to the database.
  • Concurrency Handling: Asynchronous operations improve the ability to handle multiple requests concurrently, especially when dealing with high I/O-bound tasks like database interactions.

Conclusion

Using asynchronous database operations in ASP.NET Core helps enhance the scalability, performance, and responsiveness of your web application, especially when performing I/O-bound tasks like database interactions. With async and await, you can handle multiple concurrent requests efficiently without blocking the main thread, ensuring that your application remains responsive even under heavy loads.