EfCore One-Pager
Introduction
EF Core is an object relational mapper which helps developers work with databases using .NET objects.
DbContext
-
DbContext
begins when an instance is created and ends when it is disposed. -
It is important to dispose the
DbContext
after use. This ensures that any unmanaged resources are freed and any events and hooks are unregistered to prevent memory leaks. -
DbContext
is not thread-safe. Do not share contexts between threads. Make sure to await all async calls before continuing. -
An
InvalidOperationException
can put theDbContext
in an unrecoverable state. Efcore is not designed to recover from this. -
An
AppDbContext
class must expose a public constructor with aDbContextOptions<AppDbContext>
parameter. -
Configuration can be performed by overriding the
OnConfiguring
method. -
Some applications like Blazor do not create service scopes that align with the
DbContext
unit of work lifetime. These applications may have multiple units of work within a request scope.AddDbContextFactory
can be used to register a factory for creation of DbContext instances.
DbContextOptions
-
DbContext
configuration is done via theDbContextOptionsBuilder
. -
A
DbContext
instance must be configured to use one and only one database provider. -
A database provider is configured using a specific
Use*
call. -
Examples, UseQueryTrackingBehavior, LogTo, UseLoggerFactory, EnableSensitiveDataLogging, EnableDetailedErrors, ConfigureWarnings, AddInterceptors, UseLazyLoadingProxies, UseChangeTrackingProxies.
-
The
DbContext
class does not need to be sealed, but sealing is a best practice to do so for classes not designed to be inherited from.
DbContext Threading issues
-
Efcore does not support multiple parallel operations on the same
DbContext
instance. -
Always await async calls immediately.
-
Use seperate
DbContext
instances for parallel operations.
DbContext Pooling
-
Efcore can pool context instances for high performance scenarios where the overhead of creating a new connection everytime is not desirable.
-
To enable context pooling, use
AddDbContextPool
. -
The poolsize parameter of
AddDbContextPool
controls the poolsize. It defaults to 1024. -
Once exceeded, new instances are not cached and efcore falls back to non-pooling behaviour.
Entity Modeling
Creating and Configuring a Model
-
You can configure using the Fluent Api on the OnModelCreating method.
-
Fluent Api has the highest precedence and will override conventions and data annotations.
-
Configuration is applied in the order of the methods called. Use Fluent Api.
-
Configurations can be extracted to a separate class. Grouping Configurations.
-
There are a lot of buit-in conventions that efcore uses. Check out this list here in this sample.
Entity Types
-
Entity types are exposed as
DbSet
properties on theDbContext
. -
Entities declared in
onModelCreating
are also included and so are any types found while navigating existing entity types. Including types in the model. -
Entity types can be excluded from the model. Excluding types.
-
Entity types can be included in the model but the table migration can be excluded. Excluding from migration.
-
A different table name can be specified using fluent api and data annotations. Table Names.
-
A different schema name can be specified. Table Schemas.
-
Entity types can be mapped to database view via fluent api. Efcore assumes that the view already exists and does not include it in the migration. View Mapping.
-
Entity types can be mapped to a table-valued function. It is important that the function does not take any parameters. Table Valued Function.
-
You can set a comment on the database table for documentation purposes. Table Comments.
-
Entity types that use the same CLR type are known as shared-type entity types. They need to be configured with a unique name. Entity types.
Entity Properties
-
Entity types map to tables, entity properties map to table columns.
-
All public properties with getter and setter will be included. Specific properties can be excluded. Included and Excluded properties.
-
Properties and columns have the same name. You can change it. Column names.
-
The database provider selects a data type based on the .net property type. You can control this configuration too. Column data types.
-
Maximum length only applies to array data types, such as string and byte[]. Maximum Length.
-
Efcore does not validate maximum length. It is up to the provider or data store to validate.
-
Some data types support precision and scale like decimal and datetime. Precision and Scale.
-
Different types exist for Unicode and non-unicode text. This can be configured. Unicode.
-
A collation can be defined on text columns, determining how they are compared and ordered. Column Collation
-
You can set arbitrary text comment that gets set on the database column, allowing you to document your schema. Column Comments.
-
When creating a table, efcore creates the primary key columns first, followed by properties of the entity type and owned types, and finally properties from base type. You can control that. Column Order.
Nullability, Required and Optional properties
-
If a property can be null, it is optional.
-
Optional means that the database column will be nullable.
-
If nullable reference types are enabled,
string?
will be considered optional,string
will be considered required. If nullable reference types are disabled, string will be considered optional as string is a reference type. -
You can however explicitly mark a property as required. Explicit configuration.
Keys
-
A key serves as a unique identifier for each entity instance.
-
A property name
Id
or<typename>Id
will be configured as the primary key of an entity. -
Owned entity types use different rules to define keys.
-
You can configure a single property to be the primary key. Configuring a primary key.
-
You can also configure multiple properties to be the primary key. Configuring a primary key.
-
For numeric and guid primary keys, value generation is automatically setup. For example, a numeric primary key in sql server is setup to be an Identity column.
-
Primary key constraints are created with the name
Pk_<type name>
. You can change that. Primary key name -
An alternate key serves as an alternate unique identifier for each entity instance in addition to the primary key. Alternate Keys
Generated Values
-
A column can be configured with a default value. You can configure a default value. Default values.
-
A column can be configured to have its value computed in the database, typically with an expression referring to other columns. You can have this as a virtual column or a stored column. Computed columns
-
Primary keys of type short, int. long, or Guid are set up to have values generated for inserted entities if a value isn’t provided by the application. The database provider takes care of the necessary configuration.
-
You can explicitly set value generation for non-key properties. You can configure it to have its value generated for inserted entities or you can configure it to have its value generated on add or update. Explicitly configuring value generation.
-
How these values are generated depends on the database providers. You must consult your provider’s documentation for specific value generation techniques. Sql Server Provider Value Generation.
-
A common request is to have a datetime column which records when an entity was added and when it was last updated. Database providers do not provide this out of the box. You have to configure this yourself.
-
You can use the appropriate sql function that does this. Creation Timestamp.
-
Alternatively, you can use a trigger to acheive this. Update Timestamp.
-
You can override a property that is configured for value generation, you need to simple set the property to any value that is not the CLR default value for that property’s type (null for string, 0 for int, Guid.Empty for Guid etc). Overriding value generation.
-
In some cases you may want to disable value generation that has been set up by convention. You can disable it. No value generation.
Shadow Properties
-
Shadow properties are properties that are not defined in the .NET entity class but are defined for that entity type in the EF Core model.
-
For example, you may not want to have a DateCreated and LastUpdated property in every entity class. You can create a shadow property for these in the model. The value and state of these properties are change tracked.
-
Shadow properties are mostly used for foreign key properties. They are added to the model by convention when no foreign key property has been found by convention or configured explicitly. Shadow Properties.
-
The property will be named
<navigation property name><principal key property name>
-
You can use the Fluent Api to configure any other shadow properties that you may need. Configuring Shadow Properties.
-
Shadow property values can be accessed through the ChangeTracker Api’s. Accessing Shadow Properties.
Relationships
-
A relationship defines how two entities relate to each other. It is represented by a foreign key constraint.
-
A dependent entity contains the foreign key properties. Referred to as the 'child' of the relationship.
-
A principal entity contains the primary key properties. Referred to as the 'parent' of the relationship.
-
A principal key contains the properties that uniquely identify the principal entity. This may be the primary key or an alternate key.
-
A foreign key contains the properties that store the principal key values of the parent entity.
-
A navigation property is a property on the principal/dependent entity that references the related entity.
-
A collection navigation property contains references to many related entities.
-
A reference navigation property holds a reference to a single related entity.
-
An inverse navigation property refers to an navigation property on the other end of the relationship, when discussing a particular navigation property.
-
A self referencing relationship is a relationship in which the dependent and the principal entity types are the same.
-
The most common pattern is to have navigation properties defined on both ends of the relationship and a foreign key propery defined in the dependent entity class. For more rules and details InverseProperty Sample.
-
It is not required to have a foreign key property defined in the dependent entity class. In such a case a shadow foreign key property is created. No foreign key property.
-
Including just one navigation property (no inverse navigation, and no foreign key property) is enough to have a relationship defined by convention. Single navigation property.
-
Cascade Delete will be set to Cascade for required relationships. Cascade means dependent entities are also deleted.
-
Cascade Delete will be set to ClientSetNull for optional relationships. ClientSetNull means that dependent entities not loaded into memory will remain unchanged. You must manually delete it. For entities loaded into memory, EF core will attempt to set the foreign key properties to null.
-
You can configure if a relationship is required or optional. Required or optional relationships.
-
You can use Fluent Api and DataAnnotations to configure your relationships rather than relying on convention. See here for samples.
Indexes
-
Indexes are used to make lookups based on a column more efficient.
-
An index is created in each property (or set of properties) that are used as a foreign key.
-
An index can also span more than one column. Composite Index
-
By default, indexes are not unique. You can force them to be unique. Index Uniqueness.
-
By default, index sort order is ascending. You can change that. Index sort order.
-
You can set the name of the index. Index name.
-
You can index only a subset of a column’s values, reducing the index’s size and improving performance. Index Filter.
-
You can include columns which are not part of the indexes key to improve query performance. Included Columns.
-
Check constraints allow you to define a condition that must hold true for all rows in the table. Check Constraints.