多对多关系 EF6 流畅 API

Relation Many to Many EF6 Fluent API

我正在使用 EF6 和 Fluent API 开发应用程序,但我在管理多对多关系时遇到了问题。 由于某些内部原因,Join table 具有特定格式,包括 4 个字段 - 左 ID (FK) - 右 ID (FK) - 开始日期(日期时间) - 结束日期(日期时间)

删除 link 实际上是将 EndDate 设置为非空,但我现在不知道如何在 EF6 中配置它。 另一方面,当读取 links 时,不应考虑带有 Not NULL EndDate 的记录。

你能给我一个解决方案吗?

谢谢。

Can you give me a solution ?

如果您的链接 table 有额外的列,您必须将其建模为实体,并且导航的 EndDate 逻辑需要明确。 EF 不会为您做任何事情。

我不想让它成为一个实体,因为这 2 个额外的字段是技术字段(用于记录目的)而不是功能字段。我的应用程序不应该知道它们的存在。

我想知道我是否不能使用 MapToProcedure() 函数但我不知道该怎么做???

加入 tables 和 EF

EF 为您自动执行一些操作。为此,它使用约定优于配置。如果你坚持惯例,你可以跳过一大堆常见的配置。

例如,如果您的实体有一个名为 Id 的 属性,EF 将固有地假定这是 PK。

类似地,如果两个实体类型具有相互引用的 nav props(并且两个实体之间只存在一个直接 link),那么 EF 将自动假定这些 nav props 是单一的多对多关系。 EF 将在数据库中进行连接 table,但它会将此隐藏起来,让您自己处理这两种实体类型。

For some internal reasons the Join table has a specific format including 4 fields - Left Id (FK) - Right Id (FK) - StartDate (dateTime) - EndDate (datetime)

您的连接 table 不再符合常规和自动生成的 EF 连接 table 的内容。您期望 EF 无法根据盲目约定提供一定程度的自定义可配置性,这意味着您必须显式配置它。

其次,您拥有这些额外的列这一事实意味着您希望在某个时候使用这些数据(大概是为了显示两个实体之间的历史关系。因此,依赖 EF 的自动join tables 作为 join table 并且它的内容将从 application/developer.

中隐藏

如果您不需要应用程序获取已结束的条目,那么第二个考虑因素可能对您无效。但整体观点还是成立的。

此处的解决方案是使连接记录成为它自己的显式实体。本质上,您在这里处理的不是多对多,而是处理具有两个一对多关系(两种实体类型中的每一种关系)的特定实体(join 元素)。

这使您能够准确地实现您想要的。您对 EF 可以为您自动化的期望在这种情况下根本不适用。


软删除

Deleting a link is in fact setting the EndDate as not null but i don't now how to configure it in EF6.

通常,这被称为 "soft delete" 行为,尽管此处可能略有不同。在常规软删除模式中,删除条目时,数据库会秘密保留该条目,但应用程序不知道,也不会再次看到该条目。

不清楚您是否打算让已结束的条目仍显示在应用程序中,例如关系史。如果不是这种情况,那么您的情况完全是软删除行为。

这不是您在模型级别配置的内容,而是您在数据库的 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 体系结构。如果您开始为不同类型的实体编写许多自定义规则,数据库上下文逻辑将变得混乱,并且不会很好地使用它,因为您需要考虑 SaveChanges 期间发生的多种可能操作。

注意不要将本应是业务逻辑的决策推送给 DAL。我无法为您画出这条线,这取决于您的上下文。但是评估数据库上下文是否是实现此行为的最佳位置。