Entity Framework Core CRUD Operations and Migrations

Entity Framework Core CRUD Operations and Migrations

Entity Framework Core CRUD Operations and Migrations

Entity Framework Core (EF Core) is a modern, open-source, object-database mapper for .NET. It enables developers to work with a database using .NET objects, eliminating the need for most of the data-access code that developers usually need to write.

1. Introduction to Entity Framework Core

Entity Framework Core is the lightweight, extensible, and cross-platform version of Entity Framework, the popular Object-Relational Mapper (ORM) for .NET. EF Core allows developers to work with databases using .NET objects, eliminating the need for most of the data-access code that developers usually need to write. It supports LINQ queries, change tracking, updates, and schema migrations.

1.1. Why Use EF Core?

  • Productivity: Reduces the amount of code required for data access.
  • Maintainability: Encourages a clean separation of concerns.
  • Testability: Facilitates unit testing by allowing the use of in-memory databases.
  • Cross-Platform: Works on Windows, Linux, and macOS.

2. Setting Up the Environment

Before diving into CRUD operations and migrations, it's essential to set up the development environment properly.

2.1. Installing EF Core

To get started with EF Core, you need to install the necessary packages. Using the .NET CLI, you can add the EF Core package to your project:

dotnet add package Microsoft.EntityFrameworkCore

Depending on your database provider, you'll also need to install the corresponding package. For example, for SQL Server:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer

2.2. Configuring the Database Connection

In your appsettings.json, define the connection string:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"
  }
}

Then, in your Startup.cs or Program.cs, configure the DbContext:

services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

3. Understanding the DbContext

The DbContext is the primary class responsible for interacting with the database. It manages the entity objects during runtime, including populating objects with data from a database, change tracking, and persisting data to the database.

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }

    public DbSet<Product> Products { get; set; }
}

4. Defining the Data Model

Define your entity classes that represent the tables in your database.

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

5. Implementing CRUD Operations

CRUD operations are the backbone of any data-driven application. EF Core simplifies these operations through its intuitive API.

5.1. Create Operation

To add a new record to the database:

var product = new Product { Name = "Laptop", Price = 999.99M };
_context.Products.Add(product);
_context.SaveChanges();

5.2. Read Operation

To retrieve data:

var products = _context.Products.ToList();

5.3. Update Operation

To update existing data:

var product = _context.Products.First(p => p.Id == 1);
product.Price = 899.99M;
_context.SaveChanges();

5.4. Delete Operation

To remove data:

var product = _context.Products.First(p => p.Id == 1);
_context.Products.Remove(product);
_context.SaveChanges();

6. Exploring Migrations in EF Core

Migrations are a powerful feature of Entity Framework Core. They allow you to evolve your database schema over time as your model changes, without losing existing data. Instead of manually modifying the database, you make changes to your C# classes and let EF Core handle the database updates.

6.1 What are Migrations?

Migrations act as a version control system for your database schema. Each migration captures the state of the model at a given point in time. EF Core compares the current model with the last migration and generates SQL scripts to apply the necessary changes.

6.2 Creating and Applying Migrations

To create a migration, use the following command:

dotnet ef migrations add InitialCreate

This creates a C# file representing the schema changes. Then, apply the migration with:

dotnet ef database update

This command updates the database to match your model. The __EFMigrationsHistory table tracks all applied migrations.

6.3 Updating the Model and Database

When you change your entity classes (e.g., add a new property), you create a new migration to apply those changes:

dotnet ef migrations add AddCategoryToProduct
dotnet ef database update

6.4 Reverting Migrations

If needed, you can roll back to a previous state using:

dotnet ef database update PreviousMigrationName

7. Advanced EF Core Usage

7.1 Handling Relationships in EF Core

Entity relationships are a crucial part of database design. EF Core supports three main types:

  • One-to-One: Each entity has exactly one related entity.
  • One-to-Many: One entity is related to many others.
  • Many-to-Many: Both entities are related to many instances of the other.

Example of one-to-many using Fluent API:

modelBuilder.Entity<Category>()
    .HasMany(c => c.Products)
    .WithOne(p => p.Category)
    .HasForeignKey(p => p.CategoryId);

EF Core also supports data annotations like [ForeignKey], [InverseProperty], and [Required] for relationship mapping.

7.2 Data Seeding in EF Core

Data seeding allows you to populate the database with initial data during migrations. It’s great for creating lookup tables or test data.

modelBuilder.Entity<Category>().HasData(
  new Category { CategoryId = 1, Name = "Electronics" },
  new Category { CategoryId = 2, Name = "Books" }
);

When you apply migrations, EF Core inserts this data into the respective tables.

7.3 Working with Stored Procedures

Sometimes you want to use existing stored procedures instead of writing raw SQL. EF Core supports calling stored procedures using FromSqlRaw:

var products = _context.Products
    .FromSqlRaw("EXEC GetAllProducts")
    .ToList();

EF Core 7.0 and above also allow mapping stored procedures to INSERT, UPDATE, DELETE operations directly through Fluent API.

8. Best Practices for Entity Framework Core

To build scalable, maintainable, and efficient applications using EF Core, it’s essential to follow some industry-tested best practices:

8.1 Use Asynchronous Methods

Always use async methods like ToListAsync(), FirstOrDefaultAsync(), SaveChangesAsync() to avoid blocking the main thread, especially in web applications. It improves responsiveness and throughput.

8.2 Implement the Repository Pattern

Use a repository to encapsulate all database operations and expose only what’s needed. This improves code modularity, testability, and maintainability.

8.3 Avoid Hardcoding Connection Strings

Store your connection strings in configuration files like appsettings.json. Use secrets manager or environment variables for production environments to protect sensitive information.

8.4 Use Dependency Injection for DbContext

Inject DbContext using .NET’s built-in DI container to manage lifecycle, testability, and configuration more effectively.

8.5 Apply Migrations in a Controlled Manner

Use separate environments (development, staging, production) and apply migrations through CI/CD pipelines instead of running them manually in production.

8.6 Use Logging and Monitoring

Enable EF Core logging to track queries and performance issues. Combine with application monitoring tools like Application Insights, ELK, or Serilog.

9. Common Pitfalls and How to Avoid Them

  • Lazy Loading Pitfalls: Avoid unnecessary lazy loading that can lead to N+1 query problems. Use Include() for eager loading.
  • Missing SaveChanges(): Forgetting to call SaveChanges() results in no data being persisted.
  • Tracking Issues: Modifying an entity not tracked by the context won’t result in a database update unless manually attached.
  • Hard Deletes: Use soft deletes for critical data to prevent accidental data loss.
  • Mismatched Migrations: Never manually modify migration files unless necessary. Re-generate instead using dotnet ef migrations remove and redo changes.

10. Conclusion

Entity Framework Core is a powerful tool that bridges the gap between relational databases and .NET applications. By learning how to perform CRUD operations, apply and manage migrations, model complex relationships, and follow best practices, you set yourself up to build scalable, maintainable, and modern applications that interact seamlessly with a database.

Whether you're working on a simple web API or an enterprise-grade system, mastering EF Core ensures that your application’s data access layer is efficient, testable, and easy to manage. Keep exploring advanced features like raw SQL execution, value converters, tracking behaviors, and performance optimizations to elevate your development skills even further.

11. FAQs

Q1: Can I use EF Core with MySQL or PostgreSQL?

Yes, EF Core supports various providers. Use packages like Pomelo.EntityFrameworkCore.MySql for MySQL and Npgsql.EntityFrameworkCore.PostgreSQL for PostgreSQL.

Q2: What is the difference between EF and EF Core?

EF Core is a lightweight, cross-platform rewrite of EF 6 with a modern API, better performance, and new features like shadow properties, value conversions, and global filters.

Q3: Can I use EF Core in a console application?

Yes, EF Core works in all .NET Core app types, including console, desktop, mobile, and web apps.

Q4: How do I seed data conditionally?

You can use conditional logic in your application startup to check whether data exists before inserting it, or use HasData() in migrations for fixed seeds.

Q5: How can I reset my database using EF Core?

Use dotnet ef database drop followed by dotnet ef database update to wipe and recreate your database, typically in dev environments.

Post a Comment

Post a Comment (0)

Previous Post Next Post

ads

ads

Update cookies preferences