测试回收器视图:回收器视图操作滚动得不够远



在我的常规.NET Framework应用程序中,我使用的是EF 6.x,并且还使用了一些继承,特别是:

PurchaseOrder.cs 和SaleOrder.cs 都继承自Order.cs

在从IdentityDbContext继承上下文类的OnModelCreating()中,我正在做:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

这曾经有效,但现在我正在将我的应用程序移动到 .NET Core 2.0,并且我正在使用 EF Core。在 EF Core 中实现相同目标的方法是什么?因为现在我收到错误:

System.Data.SqlClient.SqlException (0x80131904):在表"Order"上引入FOREIGN KEY约束"FK_Order_Business_CustomerId"可能会导致循环或多个级联路径。指定"删除时不执行任何操作"或"更新时不执行任何操作",或修改其他外键约束。

更新

这是艾哈迈尔回答后的代码。在我的上下文课中,我有:

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);
}

就实体而言,它们是:

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; }
}

因此,在按照 Ahmar 的建议进行操作后,当我执行update-database时,我仍然会收到相同的错误。

对于较新的 EF,您需要更改方法,下面是正确的示例:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
if (modelBuilder == null)
throw new ArgumentNullException("modelBuilder");
// for the other conventions, we do a metadata model loop
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
// equivalent of modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
entityType.SetTableName(entityType.DisplayName());
// equivalent of modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
entityType.GetForeignKeys()
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade)
.ToList()
.ForEach(fk => fk.DeleteBehavior = DeleteBehavior.Restrict);
}
base.OnModelCreating(modelBuilder);
}

Dennes Torres的解决方案,来源:https://www.red-gate.com/simple-talk/blogs/change-delete-behavior-and-more-on-ef-core/

需要在 .Net Core EF 中的每个实体上配置级联删除行为。

实体框架核心流畅 APIOnDelete方法用于指定删除主体时应对关系中的依赖实体执行的操作。

OnDelete 方法将DeleteBehavior枚举作为参数:

  • 级联 - 应删除依赖项
  • 限制 - 家属是 未受影响的
  • SetNull - 依赖行中的外键值应 更新为空

例:

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);
}

删除公司时,它会将员工表中的公司 ID 属性设置为 null。

有关更多详细信息,请参阅配置一对多关系

请确保所有引用属性都应为空,以便EF Core可以在删除时将它们设置为空。 就像CompanyId关于示例中一样。

最新更新