Train
Train

Reputation: 3496

EF Core migration adds cascade on delete in wrong direction for one to many relationship

I am using asp.net core 3 web api and EF core 3 I have a one to many relationship between 2 tables:

Task and TaskType

Task has one TaskType

TaskType has many Tasks

Here are the 2 entities:

public class TaskType
{
    public TaskType() {
        Tasks = new HashSet<Task>();
    }

    [Key]
    public Guid TaskTypeID { get;set; }
    ...
    public ICollection<Task> Tasks { get; set; }
} 

public class Task
{
    public Task() {

    }

    [Key]
    public Guid TaskID {get;set;}
    ...
    public Guid TaskTypeID { get; set; }
    [ForeignKey("TaskTypeID")]
    public TaskType TaskType { get; set; }
}

When I run the add-migration command it generates this code

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<Guid>(
        name: "TaskTypeID",
        table: "Task",
        nullable: false,
        defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));

    migrationBuilder.CreateIndex(
        name: "IX_Task_TaskTypeID",
        table: "Task",
        column: "TaskTypeID");

    migrationBuilder.AddForeignKey(
        name: "FK_Task_TaskType_TaskTypeID",
        table: "Task",
        column: "TaskTypeID",
        principalTable: "TaskType",
        principalColumn: "TaskTypeID",
        onDelete: ReferentialAction.Delete);// I want to change this to ReferentialAction.NoAction
}

protected override void Down(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropForeignKey(
        name: "FK_Task_TaskType_TaskTypeID",
        table: "Task");

    migrationBuilder.DropIndex(
        name: "IX_Task_TaskTypeID",
        table: "Task");

    migrationBuilder.DropColumn(
        name: "TaskTypeID",
        table: "Task");
}

Notice the line onDelete: ReferentialAction.Delete which obviously is an error and should cascade the other way.

To fix this, I want to change it to ReferentialAction.NoAction

and add this code to my onModelCreating in my context

modelBuilder.Entity<TaskType>()
            .HasMany(c => c.Tasks)
            .WithOne(e => e.TaskType)
            .OnDelete(DeleteBehavior.Cascade);

Is this the correct way to add cascade delete for a one to many relationship? Should I be modifying the generated migration code or is there another way to tell EF not to cascade delete the TaskType when I delete a Task?

Edit: The accepted answer helped me come up with ha solution. I should have been more specific, I needed the orphaned TaskType records. So I set the TaskTypeID FK to a nullable Guid and in my OnDelete() I set the option to ReferentialAction.SetNull

Upvotes: 0

Views: 1188

Answers (1)

Barry O&#39;Kane
Barry O&#39;Kane

Reputation: 1187

The direction is correct.

If you were to delete a Task by cascading from the delete of a TaskType then you could quite possibly leave a lot of orphaned TaskType records (assuming there was no referential integrity).

The entity TaskType depends on the Task entity, so the only valid scsenario for deleting a Task is to delete all of the associated TaskType records.

One common approach to getting around this is to use a soft delete.

Essentially add a property to the entity

public bool IsDeleted { get; set; }

and you can then know that an entity is deleted, but still maintain the correct references.

Upvotes: 3

Related Questions