【发布时间】: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 是一个字符串,似乎可以工作。如果是整数,那就不行了!
这对我来说都是一个黑客。我已经想到了一些解决方案,但它们并不实用:
- 在删除 B 时查询所有引用 B 的表并清空其外键。这太丑陋了,如果我将来添加另一个引用 B 的实体,我不想记住这样做。更不用说每当我删除某些内容时都会出现巨大的性能延迟解决所有引用。
- 向我可以信赖的每个表添加一个字符串字段,我可以检查该实体是否存在。 Blech,我不想为此添加数据库字段。
- 实施软删除并保持所有引用完整性不变 - 本质上是设置级联删除,但这将导致巨大的数据库膨胀,因为由于引用,我无法清理大量记录。不行。
我以为我用“检查引用实体中的字段是否为空”技巧解决了这个问题,但它在我不完全理解的情况下中断(如果我在引用中没有任何字符串怎么办?表?什么样的字段可以工作?整数不行。)
例如,如果我在实体 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