模型设计中指定"删除时不执行操作外键约束"?
目前,我有:
public class Status
{
[Required]
public int StatusId { get; set; }
[Required]
[DisplayName("Status")]
public string Name { get; set; }
}
public class Restuarant
{
public int RestaurantId { get; set; }
[Required]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
public string Telephone { get; set; }
[Required]
public int StatusId { get; set; }
public List<Menu> Menus { get; set; }
// NAVIGATION PROPERTIES
public virtual Status Status { get; set; }
}
public class Menu
{
public int MenuId { get; set; }
[Required]
public int RestaurantId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int StatusId { get; set; }
// NAVIGATION PROPERTIES
public virtual Status Status { get; set; }
public virtual Restaurant Restaurant { get; set; }
}
和我的数据库上下文:
public class MenuEntities : DbContext
{
public DbSet<Status> Statuses { get; set; }
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<Menu> Menus { get; set; }
}
如您所见:
- 餐厅有很多菜单
- 餐厅具有一种状态
- a 菜单属于1家餐厅
- 餐厅和菜单都有 1 个状态。(实时,隐形,草稿)
如果删除状态,我当然不想级联,因为这会把所有事情都搞砸。
更新:
Mark Oreta 在下面的示例中提到了以下内容:
modelBuilder.Entity<FirstEntity>()
.HasMany(f => f.SecondEntities)
.WithOptional()
.WillCascadeOnDelete(false);
我应该把这个代码放在哪里?在我的 MenuEntities/DbContext 类中?任何人都可以提供使用它的例子吗?
更新:现在让这个位工作了,但是这在尝试播种数据库时产生了多重性约束错误......
Multiplicity constraint violated. The role 'Menu_Status_Source' of the relationship 'LaCascadaWebApi.Models.Menu_Status' has multiplicity 1 or 0..1.
我的数据库初始化器:
http://pastebin.com/T2XWsAqk
您可以通过删除 OnModelCreate 方法中的级联删除约定来为整个上下文禁用它:
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
或者,您可以使用流畅的映射(也在 OnModelCreation 中)对每个关系执行此操作:
编辑:你会把它放在你的菜单实体中
public class MenuEntities : DbContext
{
public DbSet<Status> Statuses { get; set; }
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<Menu> Menus { get; set; }
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Menu>()
.HasRequired( f => f.Status )
.WithRequiredDependent()
.WillCascadeOnDelete( false );
modelBuilder.Entity<Restaurant>()
.HasRequired( f => f.Status )
.WithRequiredDependent()
.WillCascadeOnDelete( false );
}
}
只需使 FK 属性可为空,然后级联删除将消失。
public int? StatusId { get; set; }
对模型进行更改后,请确保通过添加 -Force 参数重新生成迁移文件。
添加迁移迁移名称 - 强制
行添加到上下文中字段的末尾;
.OnDelete(DeleteBehavior.Restrict);
把它放到你的MenuEntities
类(从DbContext
衍生的类):
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
在新的实体框架中,这些解决方案不起作用。您需要以不同的方式执行此操作,这是代码:
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/
您需要将此代码放在从 DbContext 交付的类中。