Entity Framework Core

• By OmerZ Solutions

Modern software applications depend heavily on efficient data management. As applications become larger and more complex, developers need reliable solutions that simplify database communication while maintaining performance and scalability.

Entity Framework Core (EF Core) is Microsoft's modern Object Relational Mapping (ORM) framework that enables .NET developers to work with databases using C# objects instead of writing large amounts of database-specific SQL code.

Entity Framework Core
Entity Framework Core allows developers to build powerful database-driven applications by mapping .NET objects with database tables and providing a simple programming model for data access.

What is Entity Framework Core?

Entity Framework Core is an open-source, lightweight, and cross-platform ORM framework designed for modern .NET applications. It acts as a bridge between application code and database systems.

Instead of manually writing SQL queries for every database operation, developers can use C# classes and LINQ expressions to perform data operations. EF Core automatically converts these operations into optimized SQL commands.

Why Use Entity Framework Core?

  • Reduces database development effort
  • Provides strongly typed database access
  • Supports LINQ queries
  • Automatically manages object relationships
  • Provides database migration support
  • Works with multiple database providers
  • Integrates seamlessly with ASP.NET Core

Entity Framework Core Architecture

Understanding EF Core architecture helps developers design applications that are maintainable, testable, and scalable.

The main components of Entity Framework Core include:

  • Entity Classes
  • DbContext
  • DbSet
  • Database Provider
  • Change Tracker
  • LINQ Query Provider

Entity Classes

Entity classes represent the application's data models. Each entity normally maps to a database table.

For example, a Product entity represents a Product table in the database.


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

EF Core uses these classes to create database structures and perform database operations.

DbContext in Entity Framework Core

DbContext is the most important class in EF Core. It manages database connections, tracks entity changes, and executes database operations.

It acts as a session between the application and the database.

Creating DbContext


using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : DbContext
{

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options): base(options)
    {

    }

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

}

DbSet in EF Core

DbSet represents a database table. Each DbSet property allows developers to query, insert, update, and delete records.


public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }

Installing Entity Framework Core

EF Core packages can be installed using NuGet Package Manager or .NET CLI.


dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

After installing required packages, applications can configure EF Core with their preferred database provider.

Configuring SQL Server with EF Core


builder.Services.AddDbContext<ApplicationDbContext>
(
 options => options.UseSqlServer("Server=localhost;Database=ShopDb;Trusted_Connection=True;")
);

Configuring Entities in Entity Framework Core

Entity Framework Core provides multiple ways to configure entity behavior, database mapping rules, relationships, constraints, and validation requirements. The two primary configuration approaches are Data Annotations and Fluent API.

Data Annotations in EF Core

Data Annotations are attributes applied directly to entity classes. They provide a simple way to configure database mapping and validation rules.

Example: Data Annotation Configuration


using System.ComponentModel.DataAnnotations;

public class Customer
{
    [Key]
    public int CustomerId { get; set; }

    [Required]
    [MaxLength(100)]
    public string Name { get; set; }

    [EmailAddress]
    public string Email { get; set; }

}

Common Data Annotation attributes include:

  • [Key] - Defines the primary key
  • [Required] - Makes a property mandatory
  • [MaxLength] - Defines maximum length
  • [Column] - Maps property to a database column
  • [Table] - Maps entity to a database table

Fluent API Configuration in EF Core

Fluent API provides advanced configuration capabilities and is usually preferred for large enterprise applications because it keeps database configuration separate from entity classes.

Fluent API configurations are written inside the OnModelCreating method of DbContext.


protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .HasKey(x => x.Id);

    modelBuilder.Entity<Product>()
        .Property(x => x.Name)
        .HasMaxLength(200)
        .IsRequired();

}

Advantages of Fluent API

  • Better separation of concerns
  • Supports complex database mappings
  • Keeps entity classes clean
  • Suitable for enterprise applications

Entity Framework Core Migrations

Database migrations allow developers to maintain database schema changes directly from application code.

Whenever entities are modified, migrations can update the database structure without manually writing SQL scripts.

Creating First Migration


Add-Migration InitialCreate

Using .NET CLI:


dotnet ef migrations add InitialCreate

Updating Database


Update-Database

Using .NET CLI:


dotnet ef database update

Migration Workflow

  • Create or modify entity classes
  • Generate migration
  • Review migration changes
  • Apply migration to database
  • Deploy updated application

CRUD Operations in Entity Framework Core

CRUD represents the four basic database operations:

  • Create
  • Read
  • Update
  • Delete

Create Data Using EF Core

New records can be inserted using the Add method.



var product = new Product
{
    Name = "Laptop",
    Price = 1200,
    StockQuantity = 15
};

_context.Products.Add(product);

_context.SaveChanges();

Reading Data Using EF Core

EF Core uses LINQ queries to retrieve data from databases.



var products = _context.Products.ToList();

Filtering Records



var expensiveProducts = _context.Products.Where(x => x.Price > 1000).ToList();

Updating Data Using EF Core

EF Core automatically tracks entity changes and updates modified records.



var product = _context.Products.FirstOrDefault(x => x.Id == 1);
product.Price = 1500;
_context.SaveChanges();

Deleting Data Using EF Core



var product = _context.Products.FirstOrDefault(x => x.Id == 1);
_context.Products.Remove(product);
_context.SaveChanges();

LINQ Queries in Entity Framework Core

LINQ (Language Integrated Query) allows developers to write strongly typed queries using C# syntax.

Basic LINQ Query



var customers = _context.Customers.Where(c => c.IsActive).ToList();

Selecting Specific Columns



var customerNames = _context.Customers.Select(x => x.Name).ToList();

Sorting Data



var products = _context.Products.OrderBy(x => x.Name).ToList();

Pagination with LINQ



var products = _context.Products.Skip(20).Take(10).ToList();

Understanding Change Tracking

Change Tracking is a powerful EF Core feature that automatically monitors changes made to entity objects.

When SaveChanges() is executed, EF Core detects modified objects and generates appropriate SQL statements.

Entity States

  • Added - New entity waiting for insertion
  • Modified - Existing entity with changes
  • Deleted - Entity marked for removal
  • Unchanged - No changes detected
  • Detached - Not tracked by context

Improving Read Performance with AsNoTracking()

For read-only operations, disabling tracking improves performance because EF Core does not need to maintain object state information.



var products = _context.Products.AsNoTracking().ToList();

Performance Tip: Use AsNoTracking() for reports, dashboards, search pages, and read-only APIs.

Entity Relationships in Entity Framework Core

Real-world applications usually contain multiple related entities. For example, a customer can have multiple orders, and an order can contain multiple products. EF Core provides built-in support for managing these relationships.

One-to-One Relationship

A one-to-one relationship means one entity is associated with exactly one related entity.

Example: A User has one Profile.

User Entity


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

User Profile Entity


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

Fluent API Configuration


modelBuilder.Entity<User>()
.HasOne(x => x.Profile)
.WithOne(x => x.User)
.HasForeignKey<UserProfile>(x => x.UserId);

One-to-Many Relationship

One-to-many is the most commonly used relationship in business applications.

Example: One customer can have many orders.


public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Order> Orders { get; set; }
}


public class Order
{
    public int Id { get; set; }
    public DateTime OrderDate { get; set; }
    public int CustomerId { get; set; }
    public Customer Customer { get; set; }
}

Relationship Configuration


modelBuilder.Entity<Order>()
.HasOne(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);

Many-to-Many Relationship

Many-to-many relationships allow multiple records from one entity to connect with multiple records from another entity.

Example: Students and Courses.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Course> Courses { get; set; }
}


public class Course
{
    public int Id { get; set; }
    public string Title { get; set; }
    public ICollection<Student> Students { get; set; }
}

Loading Related Data in EF Core

EF Core provides different approaches for loading related entities.

  • Eager Loading
  • Lazy Loading
  • Explicit Loading

Eager Loading

Eager loading retrieves related data together with the main entity using Include().



var orders = _context.Orders.Include(x => x.Customer).ToList();

This generates a query that retrieves orders and their customers together.

Lazy Loading

Lazy loading automatically loads related data when the navigation property is accessed.

To enable lazy loading, install:


Microsoft.EntityFrameworkCore.Proxies

Enable Lazy Loading


options.UseLazyLoadingProxies();

Explicit Loading

Explicit loading allows developers to manually load related entities when needed.



var customer = _context.Customers.First();
_context.Entry(customer).Collection(x => x.Orders).Load();

Repository Pattern with EF Core

The Repository Pattern creates an abstraction layer between application logic and database operations.

It improves maintainability, testing, and separation of responsibilities.

Repository Interface



public interface IRepository<T>
{
    IEnumerable<T> GetAll();
    T GetById(int id);
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
}

Repository Implementation



public class Repository<T> : IRepository<T> where T : class
{

private readonly ApplicationDbContext _context;

public Repository(ApplicationDbContext context)
{
    _context = context;
}

public IEnumerable<T> GetAll()
{
    return _context.Set<T>().ToList();
}

public void Add(T entity)
{
    _context.Set<T>().Add(entity);
    _context.SaveChanges();
}

}

Dependency Injection with EF Core

ASP.NET Core provides built-in dependency injection support. EF Core DbContext is normally registered through the service container.



builder.Services.AddDbContext<ApplicationDbContext>
(
options => options.UseSqlServer(connectionString)
);

Using EF Core in ASP.NET Core Web API

EF Core works naturally with ASP.NET Core Web APIs for building modern REST applications.

API Controller Example



[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{

private readonly ApplicationDbContext _context;

public ProductsController(ApplicationDbContext context)
{
    _context = context;
}

[HttpGet]
public IActionResult GetProducts()
{
    var products = _context.Products.ToList();
    return Ok(products);
}

}

Transactions in Entity Framework Core

Transactions ensure multiple database operations either complete successfully or fail together.



using var transaction = _context.Database.BeginTransaction();

try
{
    _context.Products.Add(product);
    _context.SaveChanges();
    transaction.Commit();
}
catch
{
    transaction.Rollback();
}

Raw SQL Queries in EF Core

Although LINQ is recommended, EF Core also supports executing raw SQL queries.



var products = _context.Products.FromSqlRaw("SELECT * FROM Products").ToList();

Global Query Filters

Global Query Filters automatically apply conditions to every query for an entity.

A common example is implementing soft delete functionality.



modelBuilder.Entity<Product>()
.HasQueryFilter(
x => !x.IsDeleted
);

Entity Framework Core Performance Optimization

Performance is an important consideration when building enterprise applications. EF Core provides several features that help developers create fast and scalable database solutions.

Use AsNoTracking for Read Operations

Tracking is useful when updating entities, but it creates additional overhead for read-only scenarios.



var customers = _context.Customers.AsNoTracking().ToList();

Using AsNoTracking improves query performance and reduces memory usage.

Avoid Loading Unnecessary Data

Applications should retrieve only the required columns instead of loading complete entities.



var customerNames = _context.Customers.Select(x => new{x.Id,x.Name}).ToList();

Use Pagination for Large Data Sets

Loading thousands of records at once can reduce application performance. Pagination improves response time and database efficiency.



var products = _context.Products.OrderBy(x => x.Id).Skip(pageSize * pageNumber).Take(pageSize).ToList();

Compiled Queries in EF Core

Compiled queries improve performance for frequently executed queries by caching the query translation process.



private static readonly Func<ApplicationDbContext,int,Product> GetProduct = EF.CompileQuery(
(context, id) =>
context.Products.First(x => x.Id == id)
);

Split Queries

When loading multiple related collections, EF Core may generate large joins. Split queries execute multiple SQL statements to improve performance.



var customers = _context.Customers.Include(x => x.Orders).AsSplitQuery().ToList();

Handling Concurrency in EF Core

Concurrency handling prevents users from accidentally overwriting changes made by other users.

Using RowVersion



public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

EF Core checks the original version before updating the record.

Value Converters in EF Core

Value converters transform property values when storing and retrieving data.

Example: Saving an enum as a string.



modelBuilder.Entity<Order>()
.Property(x => x.Status)
.HasConversion<string>();

Owned Entity Types

Owned entities represent objects that do not have their own identity and belong to another entity.



public class Address
{
    public string City { get; set; }
    public string Country { get; set; }
}


public class Customer
{
    public int Id { get; set; }
    public Address Address { get; set; }
}

Testing Entity Framework Core Applications

Testing database logic is important for building reliable applications. EF Core supports different testing approaches.

  • In-memory database testing
  • SQLite testing database
  • Integration testing with real databases

Using In-Memory Database



services.AddDbContext<ApplicationDbContext>
(
options => options.UseInMemoryDatabase("TestDatabase")
);

Common EF Core Mistakes to Avoid

  • Using tracking for every query
  • Loading unnecessary related data
  • Putting business logic inside DbContext
  • Ignoring database indexing
  • Creating extremely large DbContext classes
  • Skipping migration management
  • Using raw SQL unnecessarily

Entity Framework Core Best Practices

  • Use separate projects for Domain, Application, Infrastructure, and API layers.
  • Keep DbContext focused on database operations.
  • Use Fluent API for complex configurations.
  • Apply migrations carefully in production environments.
  • Use asynchronous methods for scalable applications.
  • Optimize queries before increasing infrastructure resources.
  • Use dependency injection instead of creating DbContext manually.

Async Operations in EF Core

Asynchronous database operations improve application scalability by freeing server threads while waiting for database responses.



var products = await _context.Products.ToListAsync();

Frequently Asked Questions About EF Core

Is Entity Framework Core free?

Yes. Entity Framework Core is an open-source framework provided by Microsoft and can be used in commercial applications.

Is EF Core faster than traditional ADO.NET?

ADO.NET can provide lower-level database control, but EF Core provides higher developer productivity and includes many optimization features.

Can EF Core work with databases other than SQL Server?

Yes. EF Core supports multiple database providers including PostgreSQL, MySQL, SQLite, Oracle, and Cosmos DB.

Should I use Repository Pattern with EF Core?

It depends on application complexity. Many enterprise applications use repositories for abstraction, testing, and separation of responsibilities.

Conclusion

Entity Framework Core has become one of the most important technologies in the .NET ecosystem for building modern database-driven applications.

With features such as LINQ queries, migrations, relationship management, change tracking, and performance optimization, EF Core allows developers to build scalable and maintainable enterprise solutions.

A strong understanding of EF Core architecture and best practices helps development teams create applications that are easier to maintain, test, and expand in the future.

Need Help Building Enterprise .NET Applications?

OmerZ Solutions helps businesses build scalable, secure, and high-performance ASP.NET Core and .NET applications.

Contact Us