实体框架级联删除(继承)
Posted
技术标签:
【中文标题】实体框架级联删除(继承)【英文标题】:Entity Framework Cascade Delete (Inheritance) 【发布时间】:2020-08-27 22:47:27 【问题描述】:我已经阅读了我能找到的所有内容,但我仍然无法解决我的问题。我正在使用 PostgreSQL,我有一个抽象类和一个子类。我希望在删除父级时也删除所有相关的依赖项。
这是我的班级的样子:
public abstract class NotificationModel
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid id get; set;
public string type get; set;
// and other common fileds
public abstract NotificationModel buildObject(JObject json);
我的孩子班:
class SmsNotificationModel : NotificationModel
public override NotificationModel buildObject(JObject json)return dummyObj;
public SmsBody Body get; set;
public Guid Fk_sms get; set;
还有短信正文
class SmsBody
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id get; set;
public List<string> Recipients get; set;
public string Route get; set;
//edit
public SmsNotificationModel smsNotModel get; set;
在 DbContext 中:
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<SmsNotificationModel>()
.HasOne(em => em.Body)
.WithOne(d => d.smsNotModel)
.HasForeignKey<SmsNotificationModel>(f => f.Fk_sms)
.OnDelete(DeleteBehavior.Cascade);
base.OnModelCreating(modelBuilder);
我不明白我做错了什么。该表被标记为级联,但是当我尝试删除它时它根本不起作用。有人可以给我一些关于如何设置的提示吗?
==== 稍后编辑
我有一个用于删除的通用仓库(模板参数是 NotificationModel 抽象类)
public class GenericRepository<T> : IGenericRepository<T> where T :class
private readonly ApplicationDbContext _context;
private DbSet<T> table = null;
public GenericRepository(ApplicationDbContext _context)
this._context = _context;
table = _context.Set<T>();
public void Delete(object id)
T existing = table.Find(id);
table.Remove(existing);
【问题讨论】:
你的意思是删除某个对象的实例?你如何删除对象? 嗨@Pribina。当我从表实体 SmsNotification 中删除时,我还想删除 SMSBody 详细信息。对于对象删除,我有一个通用存储库和删除方法:_context.NotificationsModel.Remove(object)。我不知道我是否从抽象类表中删除了一个问题(NotificationModel 而不是 SmsNotificationModel 女巫是音乐会类)。感谢重播。 你在打电话给_context.Save()
吗?
@VRoxa 是的。这也无济于事(没有错误,没有警告,保存上下文也很好)它所做的只是删除父类(NotificationModel),它不会进一步转到 SmsNotificationModel。
我明白了。你的SmsBody
必须有一个Notification
属性,可以调用... HasOne(em => em.Body).WithOne(body => body.Notification /* or whatever you call this new property */);
。您可以阅读更多关于此here 的信息。另外,别忘了Add-Migration
和Update Database
。
【参考方案1】:
应用于后期场景的一对一关系配置。 实体定义。
短信通知
public class SmsNotificationModel : NotificationModel
public SmsBody Body get; set;
// ...
短信正文
public class SmsBody
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id get; set;
// ...
// I moved the Id relation here.
// To me, it seems like Notification is the one-level-up absatraction model.
// This may be changed at any time.
public SmsNotificationModel SmsNotModel get; set;
public Guid SmsNotificationModelId get; set;
另外,顺便说一句,我上课了public
。我不确定这是否重要,因为我相信 Entity Framework 需要从它自己的程序集访问我们的程序集。
然后,配置OnModelCreating
。
public class YourContext : DbContext
// ...
public DbSet<SmsNotificationModel> Notifications get; set;
public DbSet<SmsBody> SmsBodies get; set;
protected override void OnModelCreating(ModelBuilder builder)
// ...
builder.Entity<SmsNotificationModel>(entity =>
// Configures the One-To-One relationship
// and the OnDelete behavior, as well.
entity.HasOne<SmsBody>(notification => notification.Body)
.WithOne(body => body.SmsNotModel)
.HasForeignKey<SmsBody>(body => body.SmsNotificationModelId)
.OnDelete(DeleteBehavior.Cascade);
);
还有,为了完成,数据访问层。 我不知道通用约束是否符合 Entity Framework 政策。我相信如果有的话。 我只是想提一下我要走的路。
public interface IRepository<TEntity> : IDisposable
// CRUD methods...
void Delete(TEntity entity);
void Delete(Expression<Func<TEntity, bool>> expression);
void Save();
我喜欢有一个定义所有 CRUD 操作的接口。甚至是 IAsyncRepository
,它定义了相同的操作,但异步。
public class SmsRepository : IRepository<SmsNotificationModel>
private readonly YourContext _context;
public SmsRepository(YourContext context) => _context = context;
// CRUD operations implementation ...
public void Delete(SmsNotificationModel entity)
_context.Notifications.Remove(entity);
如果您遇到任何问题,您可以继续阅读extended explanation。
希望对你有帮助。
【讨论】:
感谢您抽出宝贵时间 Roxa。我终于按照你的建议解决了这个问题。以上是关于实体框架级联删除(继承)的主要内容,如果未能解决你的问题,请参考以下文章