Setting Up

Contexts

A context is a non-abstract class that inherits from DbContext and exposes a number of entity collections in the form of DbSet<T> properties.

An important function of a context is to track changes to entities so that when we are ready to save our changes, it knows what to do. Each entity tracked by the context will be in one of the following states: unchanged, modified, added, deleted, or detached.

A context can be thought of as a sandbox in which we can make changes to a collection of entities and then apply those changes with one save operation.

public class ProjectsContext : DbContext {
  public DbSet<Resource> Resources { get; private set; }  
  public DbSet<Project> Projects { get; private set; }
  public DbSet<Customer> Customers { get; private set; }
  public DbSet<Technology> Technologies { get; private set; }
}

The DbContext class offers two public constructors, allowing the passing of context options:

public class ProjectsContext : DbContext {
  public ProjectsContext(string connectionString) : base (GetOptions(connectionString))
  {
  }

  public ProjectsContext(DbContextOptions options) : base(options)
  {
  }

  private static DbContextOptions GetOptions(string connectionString) {
    var modelBuilder = new DbContextOptionsBuilder();
    return modelBuilder.UseSqlServer(connectionString).Options;
  }
}

Context options include the specific database provider to use, its connection string, and other applicable properties.

EF Core’s DbContext class has some infrastructure methods that it calls automatically at certain times:

  • OnConfiguring: Called automatically when the context needs to configure itself—setting up providers and connection strings, for example—giving developers a chance to intervene.

  • OnModelCreating: Called automatically when Entity Framework Core is assembling the data model.

  • SaveChanges: Called explicitly when we want changes to be persisted to the underlying data store. Returns the number of records affected by the saving operations.

Entities

An entity is just a class that is mapped to an Entity Framework context, and has an identity (a property that uniquely identifies instances of it).

In domain-driven design (DDD) parlance, it is said to be an aggregate root if it is meant to be directly queried.

An entity is usually persisted on its own table and may have any number of business or validation methods.

  • An entity needs to have at least a public parameterless constructor.

  • An entity always has an identifier property, which has the same name and ends with Id.

A domain model where its entities have only properties (data) and no methods (behavior) is sometimes called an Anemic Domain Model.

References

A reference from one entity to another defines a bidirectional relation. There are two types of reference relations:

  • Many-to-one relationship

  • One-to-one relationship

public class Project {
  //one endpoint of a many-to-one relation.
  public Customer Customer { get; set; }
  //one endpoint of a one-to-one relation.
  public ProjectDetail Detail { get; set; }
}

public class ProjectDetail {
  //the other endpoint of a one-to-one relation.
  public Project Project { get; set; }
}

public class Customer {
  //the other endpoint of a many-to-one relation.
  public ICollection<Project> Projects { get; protected set; }
}

By merely looking at one endpoint, we cannot immediately tell what its type is (one-to-one or many-to-one), we need to look at both endpoints.

Collections

Collections of entities represent one of two possible types of bidirectional relations:

  • One-to-many relationship

  • Many-to-many relationship

public class Project 
{
    public Project() 
    {    
        ProjectResources = new HashSet<ProjectResource>();  
    }
    
    public ICollection<ProjectResource> ProjectResources { get; protected set; }
}

References and collections are collectively known as navigation properties, as opposed to scalar properties.

Configuring the database provider

Entity Framework is database-agnostic, but that means that each interested party—database manufacturers or others—must release their own providers so that Entity Framework can use them. Out of the box, Microsoft makes available providers for SQL Server 2012, including Azure SQL Database, SQL Server Express, and SQL Server Express LocalDB, but also for SQLite and In Memory.

EF determines which connection to use through a new infrastructure method of DbContext, OnConfiguring, where we can explicitly configure it. Also, you can pass the configuration using the constructor that takes a DbContextOptions parameter.

Entity Framework needs to know how it should translate entities (classes, properties, and instances) back and forth into the database (specifically, tables, columns, and records). For that, it uses a mapping, for which two APIs exist.

Last updated