Implements EF Cascade Delete for a required entity property and EF SetNull for an optional entity property.

GitHub Repository: djaus2/mslearn-staticwebsite-3entities main Branch.


The app is for helpers to volunteer for assistance tasks at a track meet. Entity Framework Core is used with the main entities being Round, Helper and Activity. A Helper volunteers and performs an Activity at a Meet (called a Round).


As things stand thus far with the web app, if you try to delete a Round or Helper that have been assigned to an Activity, it fails. You get a Foreign Key error. The desired behaviour is to nullify the helper property of all relevant activities when a helper is deleted and to delete all of the relevant the activities if a round is deleted.

  • The Helper property of an Activity is only assigned when a helper volunteers for that activity and so is Optional … it can be null. Deleting a helper requires any activities with that helper assigned, to have the helper property Set to Null when that helper is deleted.
  • An Activity must have a Round property and so is a Required property. If that round is deleted then all activities for that round must be deleted as well … Casecade Delete.

The Cascade Delete is implemented in EF in the Activity Model is built when the Migration is generated, by specifying the Round property as Required. Note that helper has no similar directive. It defaults to Optional (nullable).

    public class Activity
    {
        [Key]
        [Column("Id")]
        public int Id { get; set; } 

        ...

        //This can be null, its an Unassigned Task:
        [Column("Helper")]
        public Helper Helper { get; set; }

        [Column("Round")]
        [Required]
        public Round Round { get; set; }

    }

Implementation of Deletions.

This requires the Helper class to have a collection of all Activities that have that helper assigned it it. This is implemented as a property of the Helper, but is not saved to the database. It is embellished when the helper is retrieved using its Id in its DELETE function using Include, like in the Activity GET function. The class property needs a JsonIgnore directive, otherwise you get a Self referencing loop detected error message.

    public class Helper
    {
        [Key]
        [Column("Id")]

        ...

        [JsonIgnore]
        public ICollection<Activity> Activitys { get; set; }
    }

The code in the Helper DELETE function is as follows showing the Include call to get the activities for that helper.

    var helper = _context.Helpers
            .Where(l => l.Id == helperId)
            .Include(l => l.Activitys)
            .FirstOrDefault();
    if (helper != null)
    {
        _context.Remove(helper);
        var result = await _context.SaveChangesAsync();
    }

The code for Rounds is exactly the same. Note, no mention of Cascade Delete is required here.

    public class Round
    {
        [Key]
        [Column("Id")]
        public int Id { get; set; }

        ...

        [JsonIgnore]
        public ICollection<Activity> Activitys { get; set; }
    }
    var round = _context.Rounds
        .Where(l => l.Id == roundId)
        .Include(l => l.Activitys)
        .FirstOrDefault();

    if (round != null)
    {
        _context.Remove(round);
        var result = await _context.SaveChangesAsync();
    }
    modelBuilder.Entity("Data.Activity", b =>
    {
        b.HasOne("Data.Helper", "Helper")
            .WithMany("Activitys")
            .HasForeignKey("HelperId");

        b.HasOne("Data.Round", "Round")
            .WithMany("Activitys")
            .HasForeignKey("RoundId")
            .OnDelete(DeleteBehavior.Cascade)
            .IsRequired();
    });

ActivityHelpersContextModelSnapshot.cs

Footnote

When you perform add-migration, note that without the property
public ICollection<Activity> Activitys { get; set; }
in Helper and Round you don’t get:
.WithMany("Activitys") but you just get
.WithMany()
in the Model above which is part of the scaffolding needed to get this all to work.
It’s used in the line:
.Include(l => l.Activitys)
in the DELETE functions to get the relevant activities.


Posts in this series: An Azure Static Web App with EF

  1. Multiple Entities and LocalStorage
  2. Index of the Repository This post.
  3. Entity Framework Core Implementation
  4. Cascade and SetNull Deletions This post.

 TopicSubtopic
   
 This Category Links 
Category:Web Sites Index:Web Sites
  Next: > An Azure Static Web App with EF
<  Prev:   An Azure Static Web App with EF