联接表和 EF
EF 会为您自动执行一些操作。为此,它使用约定优于配置。如果你遵守约定,你可以跳过一大堆常见的配置。
例如,如果您的实体有一个名为 Id 的属性,EF 会固有地假定这是 PK。
类似地,如果两种实体类型具有相互引用的导航道具(并且两个实体之间仅存在一个直接链接),则 EF 将自动假定这些导航道具是单个多对-很多关系。 EF 会在数据库中创建一个连接表,但它会对你隐藏它,让你自己处理这两种实体类型。
由于某些内部原因,Join 表具有特定格式,包括 4 个字段 - Left Id (FK) - Right Id (FK) - StartDate (dateTime) - EndDate (datetime)
您的联接表不再符合常规和自动生成的 EF 联接表的内容。您期望 EF 基于盲目约定无法提供的自定义配置级别,这意味着您必须显式配置它。
其次,您拥有这些附加列这一事实意味着您希望在某些时候使用这些数据(大概是为了显示两个实体之间的历史关系。因此,依赖 EF 的自动连接表没有意义因为连接表和它的内容将对应用程序/开发人员隐藏。
如果您不需要应用程序获取已结束的条目,则第二个考虑可能对您无效。但总体观点仍然存在。
这里的解决方案是让连接记录成为它自己的显式实体。本质上,您在这里处理的不是多对多,而是处理具有两个一对多关系(两种实体类型中的每一种关系)的特定实体(连接元素)。
这使您能够准确地实现您想要的。在这种情况下,您对 EF 可以为您自动化的期望根本不适用。
软删除
删除链接实际上是将 EndDate 设置为非空,但我现在不知道如何在 EF6 中配置它。
一般来说,这称为“软删除”行为,尽管此处可能略有不同。在常规的软删除模式中,当一个条目被删除时,数据库会秘密保留该条目,但应用程序不知道这一点,也不会再次看到该条目。
尚不清楚您是否打算让已结束的条目仍显示在应用程序中,例如关系史。如果不是这种情况,那么您的情况是正是软删除行为。
这不是您在模型级别配置的内容,而是您在数据库的 SaveChanges 行为中覆盖的内容。我如何实现软删除的一个简单示例:
public override int SaveChanges()
{
// Get all entries of the change trackes (of a given type)
var entries = ChangeTracker.Entries<IAuditedEntity>().ToList();
// Filter the entries that are being deleted
foreach (var entry in entries.Where(entry.State == EntityState.Deleted))
{
// Change the entry so it instead updates the entry and does not delete it
entry.Entity.DeletedOn = DateTime.Now;
entry.State = EntityState.Modified;
}
return base.SaveChanges();
}
这允许您防止删除您希望应用此功能的实体,这是实现软删除的最安全方法,因为这可以作为来自使用此数据库上下文的任何消费者的数据库删除的全部内容。
您的问题的解决方案几乎相同。假设您将连接实体命名为(参见上一章)JoinEntity:
public override int SaveChanges()
{
var entries = ChangeTracker.Entries<JoinEntity>().ToList();
// Filter the entries that are being deleted
foreach (var entry in entries.Where(entry.State == EntityState.Deleted))
{
// Change the entry so it instead updates the entry and does not delete it
entry.Entity.Ended = DateTime.Now;
entry.State = EntityState.Modified;
}
return base.SaveChanges();
}
警告词
软删除往往是所有实体的包罗万象(或至少是数据库的重要部分)。因此,像我在这里所做的那样在数据库上下文级别捕获它是有意义的。
但是,如果这个实体是唯一的,因为它是软删除的,那么这更像是一个业务逻辑实现,而不是一个 DAL 架构。如果您开始为不同类型的实体编写许多自定义规则,那么 db 上下文逻辑将会变得杂乱无章,并且使用起来也不会很好,因为您需要考虑在SaveChanges 期间发生的多种可能的操作。
请注意不要将本应属于业务逻辑的决策推送给 DAL。我不能为你画这条线,这取决于你的上下文。但是评估数据库上下文是否是实现此行为的最佳位置。