【问题标题】:EF4: Filtering out referenced entities that do not existEF4:过滤掉不存在的引用实体
【发布时间】:2011-12-08 04:49:05
【问题描述】:

我有一个 Entity Framework 4 设计,允许删除引用的表(无级联删除)而不修改指向它们的实体。因此,例如实体 A 在 ID 字段中具有对实体 B 的外键引用。 B 可以被删除(并且数据库中没有 FK 约束来阻止它),所以如果我查看 A.B.ID 它始终是一个有效字段(因为所有这些都是返回 A 中的 ID 字段),即使没有由于先前的删除,具有该 ID 的记录 B。这是设计使然,我不希望级联删除,我需要 A 记录保留一段时间以进行审计。

问题在于过滤掉不存在的已删除记录并不像听起来那么容易。例如,如果我这样做:

from c in A
select A.B.somefield;

这会在生成的 SQL 中产生一个 OUTER JOIN,因此它会拾取所有 A 记录,即使它们引用了丢失的 B 记录。所以,我一直用来解决这个问题的技巧(因为我想不出更好的方法!)是添加一个 where 子句来检查引用的 B 记录中的字符串字段。如果 B 实体中的该字段为空,那么我假设 B 不存在。

from c in A
where c.B.somestringfield != null
select A.B.somefield;

如果 B.somestringfield 是一个字符串,似乎可以工作。如果是整数,那就不行了!

这对我来说都是一个黑客。我已经想到了一些解决方案,但它们并不实用:

  1. 在删除 B 时查询所有引用 B 的表并清空其外键。这太丑陋了,如果我将来添加另一个引用 B 的实体,我不想记住这样做。更不用说每当我删除某些内容时都会出现巨大的性能延迟解决所有引用。
  2. 向我可以信赖的每个表添加一个字符串字段,我可以检查该实体是否存在。 Blech,我不想为此添加数据库字段。
  3. 实施软删除并保持所有引用完整性不变 - 本质上是设置级联删除,但这将导致巨大的数据库膨胀,因为由于引用,我无法清理大量记录。不行。

我以为我用“检查引用实体中的字段是否为空”技巧解决了这个问题,但它在我不完全理解的情况下中断(如果我在引用中没有任何字符串怎么办?表?什么样的字段可以工作?整数不行。)

例如,如果我在实体 B 中有一个整数字段“count”,我检查它是否为空,例如:

from c in A
where c.B.count != null
select c.B.count;

我得到一堆计数为 null 的记录与结果混合在一起,实际上查询以“InvalidOperationException:转换为值类型 'Int32' 失败,因为具体化值为 null。要么结果类型的泛型参数或查询必须使用可为空的类型。”

所以我需要这样做

from c in A
where c.B.count != null
select new { count = (int?)c.B.count };

甚至可以看到空记录。所以这让我很困惑,这个查询怎么会导致结果中的记录为空。

我刚刚发现了一些东西,如果我像这样进行显式连接,SQL 是 INNER JOIN 并且一切正常:

from c in A
join j in B on A.B.ID equals j.ID
select c;

但这很糟糕。我将不得不修改大量查询以添加显式连接子句,而不是享受我通过 EF 获得的关系字段的便利。有点违背了目的,并添加了更多代码来维护。

【问题讨论】:

    标签: asp.net entity-framework-4 linq-to-entities


    【解决方案1】:

    当您说您的第一个代码 sn-p 创建了一个 OUTER JOIN 时,就是这种情况,因为 B 是实体 A 的可选导航属性。对于所需的导航属性,EF 将创建一个 INNER JOIN(在此处更详细地解释:https://stackoverflow.com/a/7640489/270591)。

    因此,除了使用直接 SQL 之外,我看到您最后一个代码 sn-p(在 LINQ 中使用显式 join)的唯一替代方法是使您的导航属性成为必需。

    在我看来,这仍然是一个非常丑陋的 hack,在其他情况下可能会出现意外行为。如果导航属性是必需的或可选的,则 EF 会向此关系添加“语义含义”,即:如果有外键!= NULL,则 必须 是相关实体,并且 EF 期望您不这样做' t 已删除数据库中 FK 约束的强制执行。

    【讨论】:

    • 谢谢,这是非常有用的信息。我并不真正了解可选与必需的导航属性,但如果将其简单地映射到 FK 约束,它肯定是有意义的。就我而言,我完全同意我只是讨厌破坏 required 的语义含义,因为该约束不是设计的,如果它可能导致意外的奇怪行为,请忘记它。在我看来,最好的方法是使用显式 LINQ 连接修改某些查询,以强制生成的 INNER JOIN 并在这些情况下获得正确的结果。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-07-05
    • 2015-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 2011-06-04
    • 2011-06-14
    • 2017-08-19
    相关资源
    最近更新 更多