In my regular .NET Framework application, I was using EF 6.x and was also using some Inheritance, specifically:
PurchaseOrder.cs and SaleOrder.cs both inherit from Order.cs
And in the OnModelCreating()
on my context class inheriting from IdentityDbContext
, I was doing:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
This used to work, but now I am moving my application to .NET Core 2.0 and I am using EF Core. What achieves the same thing in EF Core? Because right now I am getting the error:
System.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_Order_Business_CustomerId' on table 'Order' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
UPDATE
Here's the code after Ahmar's answer. In my context class, I have:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("PD");
builder.Entity<Customer>()
.HasMany(c => c.SaleOrders)
.WithOne(e => e.Customer)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<Supplier>()
.HasMany(po => po.PurchaseOrders)
.WithOne(e => e.Supplier)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<PurchaseOrder>()
.HasMany(li => li.LineItems)
.WithOne(po => po.PurchaseOrder)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<SaleOrder>()
.HasMany(li => li.LineItems)
.WithOne(po => po.SaleOrder)
.OnDelete(DeleteBehavior.SetNull);
}
And as far the Entities, they are:
public abstract class Business : IEntity
{
protected Business()
{
CreatedOn = DateTime.UtcNow;
}
public int Id { get; set; }
public string Name { get; set; }
public string TaxNumber { get; set; }
public string Description { get; set; }
public string Phone { get; set; }
public string Website { get; set; }
public string Email { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public ICollection<Address> Addresses { get; set; } = new List<Address>();
public ICollection<Contact> Contacts { get; set; } = new List<Contact>();
}
[Table("Customers")]
public class Customer : Business
{
public decimal AllowedCredit { get; set; }
public decimal CreditUsed { get; set; }
public int NumberOfDaysAllowedToBeOnMaxedOutCredit { get; set; }
public ICollection<SaleOrder> SaleOrders { get; set; }
}
[Table("Suppliers")]
public class Supplier : Business
{
public ICollection<PurchaseOrder> PurchaseOrders { get; set; }
}
public abstract class Order : IEntity
{
protected Order()
{
Date = DateTime.UtcNow;
CreatedOn = DateTime.UtcNow;
}
public int Id { get; set; }
public DateTime Date { get; set; }
public decimal ShippingCost { get; set; }
public Currency ShippingCurrency { get; set; }
public decimal ShippingConversionRate { get; set; }
public bool IsDeleted { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public ICollection<Invoice> Invoices { get; set; }
public ICollection<Note> Notes { get; set; }
}
[Table("PurchaseOrders")]
public class PurchaseOrder : Order
{
public int SupplierOrderNumber { get; set; }
public PurchaseOrderStatus Status { get; set; }
public decimal Vat { get; set; }
public decimal ImportDuty { get; set; }
public int SupplierId { get; set; }
public Supplier Supplier { get; set; }
public ICollection<PurchaseOrderLineItem> LineItems { get; set; }
}
[Table("SaleOrders")]
public class SaleOrder : Order
{
public decimal AmountToBePaidOnCredit { get; set; }
public SaleOrderStatus Status { get; set; }
public ICollection<SaleOrderLineItem> LineItems { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
}
So after doing what Ahmar suggested, I still get the same error when I do update-database
.
You need to configure cascade delete behavior on each entity in .Net Core EF.
The Entity Framework Core Fluent API OnDelete
method is used to specify the action which should take place on a dependent entity in a relationship when the principal is deleted.
The OnDelete method takes a DeleteBehavior
enum as a parameter:
Example:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int? CompanyId { get; set; }
public Company Company { get; set; }
}
protected override void OnModelCreating(Modelbuilder modelBuilder)
{
modelBuilder.Entity<Company>()
.HasMany(c => c.Employees)
.WithOne(e => e.Company).
.OnDelete(DeleteBehavior.SetNull);
}
When deleting the Company, it will set CompanyId property in Employee table to null.
Get more detail at Configuring One To Many Relationships
PS. Please make sure your all referencing properties should be null able so, EF Core can set them null on delete. like CompanyId
in about example.