Skip to content

05 - EF Core (4)

Saving data

Add Data

Use the DbSet.Add method to add new instances of your entity classes. The data will be inserted in the database when you call SaveChanges.

The Add, Attach, and Update methods all work on the full graph of entities passed to them, as described in the Related Data section. Alternately, the EntityEntry.State property can be used to set the state of just a single entity.
For example: context.Entry(blog).State = EntityState.Modified

Updating data

EF will automatically detect changes made to an existing entity that is tracked by the context. This includes entities that you load/query from the database, and entities that were previously added and saved to the database.

Simply modify the values assigned to properties and then call SaveChanges.

Deleting data

Use the DbSet.Remove method to delete instances of your entity classes.

If the entity already exists in the database, it will be deleted during SaveChanges. If the entity has not yet been saved to the database (that is, it is tracked as added) then it will be removed from the context and will no longer be inserted when SaveChanges is called.

Multiple Operations in a single SaveChanges

You can combine multiple Add/Update/Remove operations into a single call to SaveChanges

For most database providers, SaveChanges is transactional (atomic). This means all the operations will either succeed or fail and the operations will never be left partially applied.

Adding a graph of new entities.

  • If you create several new related entities, adding one of them to the context will cause the others to be added too
  • If you reference a new entity from the navigation property of an entity that is already tracked by the context, the entity will be discovered and inserted into the database.
  • If you change the navigation property of an entity, the corresponding changes will be made to the foreign key column in the database.

Removing relationships

  • You can remove a relationship by setting a reference navigation to null, or removing the related entity from a collection navigation.
  • Removing a relationship can have side effects on the dependent entity, according to the cascade delete behavior configured in the relationship.
  • By default, for required relationships, a cascade delete behavior is configured and the child/dependent entity will be deleted from the database. For optional relationships, cascade delete is not configured by default, but the foreign key property will be set to null.

Cascade delete

EF Core implements several different delete behaviors and allows for the configuration of the delete behaviors of individual relationships. EF Core also implements conventions that automatically configure useful default delete behaviors for each relationship based on the requiredness of the relationship.

There are three actions EF can take when a principal/parent entity is deleted or the relationship to the child is severed:

  • The child/dependent can be deleted
  • The child's foreign key values can be set to null
  • The child remains unchanged

Optional relationships (nullable foreign key)

Behavior Name Effect in memory Effect in DB
Cascade Entities are deleted Entities are deleted
ClientSetNull (default) Foreign key properties are set to null None
SetNull Foreign key properties are set to null Foreign key properties are set to null
Restrict None None

Required relationships (non-nullable FK)

Behavior Name Effect in memory Effect in DB
Cascade (Default) Entities are deleted Entities are deleted
ClientSetNull SaveChanges throws None
SetNull SaveChanges throws SaveChanges throws
Restrict None None

If you have entities that cannot exist without a parent, and you want EF to take care for deleting the children automatically, then use Cascade.

  • Entities that cannot exist without a parent usually make use of required relationships, for which Cascade is the default.

If you have entities that may or may not have a parent, and you want EF to take care of nulling out the foreign key for you, then use ClientSetNull

  • Entities that can exist without a parent usually make use of optional relationships, for which ClientSetNull is the default.
  • If you want the database to also try to propagate null values to child foreign keys even when the child entity is not loaded, then use SetNull. However, note that the database must support this, and configuring the database like this can result in other restrictions, which in practice often makes this option impractical. This is why SetNull is not the default.

If you don't want EF Core to ever delete an entity automatically or null out the foreign key automatically, then use Restrict. Note that this requires that your code keep child entities and their foreign key values in sync manually otherwise constraint exceptions will be thrown.

Remove cascade delete totally (my personal choice)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    // disable cascade delete
    foreach (var relationship in builder.Model
                .GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
    {
        relationship.DeleteBehavior = DeleteBehavior.Restrict;
    }
}

Configuring per relationship

Data Annotations – No

Fluent API:

1
2
3
4
modelBuilder.Entity<Post>()
    .HasOne(p => p.Blog)
    .WithMany(b => b.Posts)
    .OnDelete(DeleteBehavior.Cascade);

Providers

MS providers

  • SqlServer, SQLite, InMemory
  • Cosmos DB
  • Oracle - sample

3rd party

  • PostgreSQL - Npgsql.EntityFrameworkCore.PostgreSQL
  • MySql/MariaDB - Pomelo.EntityFrameworkCore.MySql
  • Oracle - Oracle.ManagedDataAccess.Core
  • MySql/MariaDb – Oracle, has problems with Booleans (Boolean is not a datatype in MySql – needs conversion)