'Entity Framework .net 5.0 Cascading delete doesn't seem to work in this case

I have a simple three entity relationship (EF Core 5.0), Customer has 0..n Invoices which has 0..n InvoiceLines. All running on SQL Server.

    namespace TestEF
    {
        public class Customer
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public virtual List<Invoice> Invoices { get; set; }
        }
        public class Invoice
        {
            public int Id { get; set; }
            public string Description { get; set; }
            public Customer Customer { get; set; }
            public List<InvoiceLine> InvoiceLines { get; set; }
        }
        public class InvoiceLine
        {
            public int Id { get; set; }
            public string Description { get; set; }
            public Invoice Invoice { get; set; }
        }
        public class EFTestDbContext : DbContext
        {
            public DbSet<Customer> Customers { get; set; }
            public DbSet<Invoice> Invoices { get; set; }
            public DbSet<InvoiceLine> InvoiceLines { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=Test;Integrated Security=True");
            base.OnConfiguring(optionsBuilder);
        }
        }
    }

I am trying to delete a single invoice and would expect the invoice lines to cascade delete:

            using var db = new EFTestDbContext();
            var customer = db.Customers.Where(c => c.Id == _customer1.Id).Include(c => c.Invoices).ThenInclude(i => i.InvoiceLines).Single();
            db.Invoices.Remove(customer.Invoices[0]);
            db.SaveChanges(true);

However, instead of cascading it simply sets the FK of the InvoiceLine to NULL

enter image description here

Where am I going wrong? I have it set up like in this article, and it indicates in here that EF would generate appropriate SQL to do the delete of the child rows (Posts from a Blog in this case) however, I looked at the SQL from the SSMS tracer and there was only SQL to delete the Invoice not the child rows.

exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Invoices]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;

',N'@p2 int',@p2=210

Any suggestions would be appreciated.

At request of commenter: no special configuration is done in OnModelCreating, it is "out of the box"; scripts of the database tables are below:

CREATE TABLE [dbo].[Customers](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](10) NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

CREATE TABLE [dbo].[Invoices](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Description] [nvarchar](max) NULL,
    [CustomerId] [int] NULL,
 CONSTRAINT [PK_Invoices] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[Invoices]  WITH CHECK ADD  CONSTRAINT [FK_Invoices_Customers_CustomerId] FOREIGN KEY([CustomerId])
REFERENCES [dbo].[Customers] ([Id])
GO

ALTER TABLE [dbo].[Invoices] CHECK CONSTRAINT [FK_Invoices_Customers_CustomerId]
GO

CREATE TABLE [dbo].[InvoiceLines](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LineNum] [int] NOT NULL,
    [Description] [nvarchar](max) NULL,
    [Amount] [decimal](18, 2) NOT NULL,
    [InvoiceId] [int] NULL,
 CONSTRAINT [PK_InvoiceLines] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[InvoiceLines]  WITH CHECK ADD  CONSTRAINT [FK_InvoiceLines_Invoices_InvoiceId] FOREIGN KEY([InvoiceId])
REFERENCES [dbo].[Invoices] ([Id])
GO

ALTER TABLE [dbo].[InvoiceLines] CHECK CONSTRAINT [FK_InvoiceLines_Invoices_InvoiceId]
GO




Solution 1:[1]

The documentation link specifies the FK must be required for cascade delete to be the inferred configuration. If the FK allows nulls, the default delete behavior is to set the FK to null. That's why people asked to see the OnModelCreating and the exact entity configuration.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pjs