Getting Started with EF Core: A Comprehensive Guide Part 1

Table of Contents

  1. Introduction
  2. Overview of EF Core
  3. Getting Started with EF Core
  4. Defining Relationships in EF Core
  5. EF Core vs Dapper
  6. Conclusion

Introduction

Entity Framework Core (EF Core) is a modern, lightweight, open-source object-relational mapper (ORM) for .NET applications. It provides developers with an efficient way to interact with databases using .NET objects, eliminating the need for most raw SQL code. In this first part of our EF Core series, we will cover an overview of EF Core and discuss some fundamental features, including adding a database context, dependency injection, and defining relationships such as one-to-one, one-to-many, and many-to-many.

Overview of EF Core

EF Core is a cross-platform ORM that enables developers to work with relational databases such as SQL Server, PostgreSQL, MySQL, and SQLite using .NET objects. It supports LINQ queries, change tracking, migrations, and schema generation based on your .NET models.

Key Features:

  1. Cross-Platform Support: Runs on Windows, macOS, and Linux.
  2. LINQ Support: Allows developers to write strongly typed queries using LINQ.
  3. Migration Management: Provides tools to manage database schema changes.
  4. Change Tracking: Tracks changes in your .NET objects and automatically translates them into database commands.
  5. Asynchronous Queries: Fully supports async programming, enabling better scalability.
  6. Rich Relationship Management: Simplifies handling relationships between tables with minimal configuration.
  7. Automatic Schema Creation: Generates database schema directly from your .NET models.

From an architectural perspective, EF Core is ideal for applications where maintainability, abstraction, and developer productivity are priorities. Its rich feature set simplifies complex operations, making it a suitable choice for large-scale enterprise applications.

Getting Started with EF Core

To use EF Core, you need to install the required NuGet packages and configure it in your project.

Step 1: Install EF Core Packages

# For SQL Server
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

# For Tools like Migrations
dotnet add package Microsoft.EntityFrameworkCore.Tools

Step 2: Define a Database Context

The DbContext class is the backbone of EF Core. It manages the connection to the database and facilitates CRUD operations.

using Microsoft.EntityFrameworkCore;

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

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

In this example, Products and Categories represent tables in the database.

Step 3: Configure Dependency Injection

EF Core integrates seamlessly with ASP.NET Core’s dependency injection system. To configure the DbContext, you can add it to the service container in Program.cs:

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

app.Run();

Defining Relationships in EF Core

EF Core supports various types of relationships between entities:

1. One-to-One Relationship

A one-to-one relationship occurs when one entity is related to exactly one other entity.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public UserProfile Profile { get; set; }
}

public class UserProfile
{
    public int Id { get; set; }
    public string Bio { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
        .HasOne(u => u.Profile)
        .WithOne(p => p.User)
        .HasForeignKey<UserProfile>(p => p.UserId);
}

2. One-to-Many Relationship

A one-to-many relationship occurs when one entity is related to multiple other entities.

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Product> Products { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Category>()
        .HasMany(c => c.Products)
        .WithOne(p => p.Category)
        .HasForeignKey(p => p.CategoryId);
}

3. Many-to-Many Relationship

A many-to-many relationship occurs when multiple entities are related to multiple other entities.

public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Book> Books { get; set; }
}

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public ICollection<Author> Authors { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Author>()
        .HasMany(a => a.Books)
        .WithMany(b => b.Authors)
        .UsingEntity(j => j.ToTable("AuthorBooks"));
}

EF Core vs Dapper

EF Core and Dapper are two popular ways to interact with databases in .NET applications. Here is a comparison of their key differences:

FeatureEF CoreDapper
TypeFull-fledged ORMMicro-ORM
QueryingLINQ and strongly-typed queriesRaw SQL and dynamic queries
Ease of UseEasier to set up relationshipsSimpler for straightforward queries
PerformanceSlightly slower due to abstractionFaster for read-heavy applications
FeaturesChange tracking, migrations, etc.Lightweight with fewer built-in tools
Learning CurveModerate, especially for beginnersLow, easier for developers familiar with SQL

Architectural Perspective

From an architect’s point of view, EF Core offers:

  • Higher abstraction: Simplifies database operations, reducing boilerplate code.
  • Maintainability: With migrations and schema management, it becomes easier to handle changes.
  • Standardization: Ensures consistency across the application through the use of LINQ and conventions.
  • Productivity Gains: Developers can focus more on business logic rather than database intricacies.

Dapper, on the other hand, is preferred when:

  • Performance is critical: For applications requiring extremely fast read operations.
  • Fine-grained control: When developers need precise SQL queries for complex operations.
  • Lightweight solutions: For small-scale applications or services with limited relational complexity.

When to Use EF Core

  • Applications with complex relationships and frequent schema updates.
  • Scenarios where automatic change tracking and migrations are beneficial.

When to Use Dapper

  • High-performance scenarios requiring raw SQL.
  • Applications with simpler database requirements and no need for ORM features.

Conclusion

In this first part of our EF Core series, we explored the basics of EF Core, including setting up a database context, integrating it with ASP.NET Core through dependency injection, and defining relationships between entities. From an architectural standpoint, EF Core provides abstraction, maintainability, and developer productivity, making it a strong choice for enterprise applications. We also compared EF Core with Dapper to understand their differences and use cases. In the next part, we will dive into advanced EF Core features such as querying, performance optimization, and migrations.

Leave a comment