Sobes.tech
Middle

How does Entity Framework work?

sobes.tech AI

Answer from AI

Entity Framework (EF) is an ORM (Object-Relational Mapper) for .NET. It allows working with databases using .NET domain objects, eliminating the need to write most of the data access code.

Working principles:

  1. Mapping: EF establishes correspondence between C# classes and database tables, as well as between class properties and table columns.
  2. LINQ to Entities: Enables writing data queries in familiar LINQ, which EF translates into SQL queries for execution in the database.
  3. DataContext / DbContext: The main class representing a session with the database. It tracks object changes, executes queries, and saves changes.
  4. Change Tracking: EF tracks the state of objects loaded from the database (Added, Modified, Deleted, Unchanged, Detached).
  5. SQL Generation: Based on LINQ queries and tracked changes, EF generates corresponding SQL commands (SELECT, INSERT, UPDATE, DELETE).
  6. Command Execution: The generated SQL commands are sent to the database for execution.
  7. Result Mapping: The results of SQL query execution are converted back into .NET domain objects.

Workflow:

  1. Define the data model (POCO classes).
  2. Create a class inheriting from DbContext.
  3. Configure the database connection.
  4. Write LINQ queries to retrieve, add, modify, or delete data.
  5. Call the SaveChanges() method to persist tracked changes to the database.

EF supports two main development approaches:

  • Code-First: The data model is defined using POCO classes, and the database is generated based on this model (including migrations for schema updates).
  • Database-First: The data model is generated from an existing database.

Key components:

  • DbContext: Manages the session with the database.
  • DbSet<TEntity>: Represents a collection of entities of a specified type in the context or database.
  • DbChangeTracker: Tracks entity changes.
  • Migrations: Tool for managing schema evolution in Code-First approach.
  • Data provider (Database Provider): Adapter between EF and a specific DBMS.
// Example of using DbContext and DbSet
public class ApplicationDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Order> Orders { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // Example configuration for SQL Server
        optionsBuilder.UseSqlServer("ConnectionString");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Additional model configuration (e.g., Fluent API)
        modelBuilder.Entity<Order>()
            .HasOne(o => o.User)
            .WithMany(u => u.Orders);
    }
}

public class User
{
    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 string ProductName { get; set; }
    public decimal Quantity { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
}

// Example of data query and save
public class DataAccess
{
    public void AddNewUser(string name)
    {
        using (var context = new ApplicationDbContext())
        {
            var newUser = new User { Name = name };
            context.Users.Add(newUser); // Adds to DbSet, EF tracks state as Added
            context.SaveChanges(); // Generates and executes INSERT SQL
        }
    }

    public List<Order> GetUserOrders(int userId)
    {
        using (var context = new ApplicationDbContext())
        {
            // LINQ query, will be converted to SELECT SQL with JOIN
            return context.Orders
                .Where(o => o.UserId == userId)
                .Include(o => o.User) // Eager load related User object
                .ToList(); // Executes SQL and returns list of Order objects
        }
    }

    public void UpdateUserName(int userId, string newName)
    {
        using (var context = new ApplicationDbContext())
        {
            var user = context.Users.Find(userId); // Loads user, EF tracks state as Unchanged
            if (user != null)
            {
                user.Name = newName; // EF detects change, state becomes Modified
                context.SaveChanges(); // Generates and executes UPDATE SQL
            }
        }
    }
}

Entity states table:

State Description
Added Object added to context but not yet saved to DB.
Unchanged Object loaded from DB and not modified.
Modified Object loaded from DB and modified.
Deleted Object marked for deletion from DB.
Detached Object is not tracked by EF context.