[C#] How to Delete Rows with Entity Framework Core

目次

Overview

This implementation explains how to physically delete a specific record (row) from a database using Entity Framework Core (EF Core). By retrieving the target data, passing it to the Remove method, and calling SaveChangesAsync, a DELETE SQL statement is executed against the database.

Specifications (Input/Output)

  • Input: The ID of the data to be deleted (integer).
  • Output: The result of the deletion process (success or error message).
  • Prerequisites: .NET 6.0 or higher, Microsoft.EntityFrameworkCore.InMemory (for testing purposes).

Basic Usage

  1. Retrieve the data you want to delete.
  2. Pass the target object to the DbSet.Remove method.
  3. Commit the changes using SaveChangesAsync.
// 1. Retrieve the target to delete
var item = await context.Items.FindAsync(targetId);

if (item != null)
{
    // 2. Mark for deletion
    context.Items.Remove(item);
    
    // 3. Execute the DELETE statement in the database
    await context.SaveChangesAsync();
}

Full Code Example

The following is a console application scenario for “Deleting old system logs by ID.” It uses an in-memory database for demonstration. You will need the Microsoft.EntityFrameworkCore.InMemory package.

dotnet add package Microsoft.EntityFrameworkCore.InMemory
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

public class Program
{
    public static async Task Main()
    {
        var options = new DbContextOptionsBuilder<SystemLogContext>()
            .UseInMemoryDatabase("LogDb")
            .Options;

        // --- 1. Prepare Initial Data ---
        using (var context = new SystemLogContext(options))
        {
            if (!await context.SystemLogs.AnyAsync())
            {
                context.SystemLogs.Add(new SystemLog { Id = 1, Message = "Server started", CreatedAt = DateTime.Now.AddHours(-2) });
                context.SystemLogs.Add(new SystemLog { Id = 2, Message = "Connection warning", CreatedAt = DateTime.Now.AddHours(-1) });
                await context.SaveChangesAsync();
            }
        }

        // --- 2. Execute Deletion ---
        using (var context = new SystemLogContext(options))
        {
            var worker = new LogCleaner(context);
            // Delete the log with ID: 2
            await worker.DeleteLogAsync(2);
        }

        // --- 3. Verify Results ---
        using (var context = new SystemLogContext(options))
        {
            var logs = await context.SystemLogs.ToListAsync();
            Console.WriteLine($"[Current Log Count]: {logs.Count}");
            foreach (var log in logs)
            {
                Console.WriteLine($" - ID:{log.Id} {log.Message}");
            }
        }
    }
}

// Business Logic Class
public class LogCleaner
{
    private readonly SystemLogContext _context;

    public LogCleaner(SystemLogContext context)
    {
        _context = context;
    }

    public async Task DeleteLogAsync(int logId)
    {
        // Search for the target to delete
        var log = await _context.SystemLogs.FindAsync(logId);

        if (log == null)
        {
            Console.WriteLine($"Error: Log with ID {logId} was not found.");
            return;
        }

        // Set state to deleted (Database is not changed yet)
        _context.SystemLogs.Remove(log);

        // Commit changes (Executes the DELETE statement)
        await _context.SaveChangesAsync();

        Console.WriteLine($"Success: Log with ID {logId} has been deleted.");
    }
}

// Entity Definition
public class SystemLog
{
    public int Id { get; set; }
    public string Message { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
}

// DbContext Definition
public class SystemLogContext : DbContext
{
    public SystemLogContext(DbContextOptions<SystemLogContext> options)
        : base(options) { }

    public DbSet<SystemLog> SystemLogs => Set<SystemLog>();
}

Example Output

Success: Log with ID 2 has been deleted.
[Current Log Count]: 1
 - ID:1 Server started

Customization Points

  • Bulk Deletion: If you want to delete multiple records at once, use RemoveRange(IEnumerable<TEntity>).C#var oldLogs = context.SystemLogs.Where(x => x.CreatedAt < DateTime.Now.AddDays(-30)); context.SystemLogs.RemoveRange(oldLogs);
  • Soft Deletion: If you want to keep the data but mark it as deleted, do not use Remove. Instead, implement an update process that sets a flag like IsDeleted = true.
  • Related Data Deletion: Depending on your relationship configuration (e.g., OnDelete: Cascade), deleting a parent record might automatically delete child records. Check your foreign key constraints to prevent unintended data loss.

Important Notes

  • Retrieval Cost: Generally, you must load the data from the database into memory (SELECT) before calling Remove. Loading large amounts of data just to delete it can hurt performance (see Advanced Application below).
  • Null Check: Passing null to the Remove method (from a failed FindAsync or FirstOrDefaultAsync) will cause an exception or unexpected behavior. Always verify the data exists first.
  • Referential Integrity Errors: Attempting to delete data that is referenced by other tables may result in a constraint error from the database. Implement exception handling (DbUpdateException) or manage dependencies properly.

Advanced Application

In EF Core 7.0 and later, you can use ExecuteDeleteAsync to perform deletions directly on the database without retrieving the data first. This reduces network traffic and is extremely fast.

// Skip the SELECT query and DELETE matching data directly
int deletedCount = await _context.SystemLogs
    .Where(x => x.Id == 2)
    .ExecuteDeleteAsync();

Console.WriteLine($"{deletedCount} record(s) deleted.");

Conclusion

For bulk deletions where performance is critical, consider using ExecuteDeleteAsync available in EF Core 7 and later.

Standard deletion follows the steps: Retrieve -> Remove -> SaveChangesAsync.

Always perform a null check to ensure the target exists before attempting to delete it.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次