使用 Linq-to-SQL 如何删除具有空外键的行?

3

我有一个名为tblOvrdImpVolsType的表,其中有两个外键列都可以为空。当这一行中的一个外键列为空时,我使用Linq-To-SQL删除此表中的一行时遇到了问题。以下是我的代码:

using (Databases.Global db = new Databases.Global())
{
    db.Log = Console.Out;
    var records = from iv in db.tblOvrdImpVolsType
                    join sm in db.tblSecurityMasterType 
                       on iv.FkSecurity equals sm.PkSecurity
                    where sm.Name == name
                    select iv; //returns only 1 record

    db.tblOvrdImpVolsType.DeleteAllOnSubmit<MyTableType>(records);

    int numDeletes = db.GetChangeSet().Deletes.Count; // = 1
    db.SubmitChanges(); //deletes 0 records
}
  • Databases.Global继承自DataContext并包含我使用的表。

  • tblOvrdImpVolsType有两个可空的外键列(key1和key2)

  • 我关心的行具有这些关键值(key1=9898,key2=null)

  • 在我的C#代码中,key1和key2的数据类型都是int?CanBeNull=true

  • GetChangeSet()显示将删除一条记录,但当我检查数据库时,该行显然未被删除。

  • 不会抛出任何异常。

以下是DataContext生成的SQL:

DELETE FROM [tblOvrdImpVols] WHERE ([key1] = @p0) AND ([key2] = @p1)
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [9898]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [Null]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.17929

我认为问题在于[key2] = @p1这一部分。因为我关心的key2值为null,所以SQL查询出现了问题。以下SQL查询说明了这一点。唯一的区别是key2条件中的is=

select * FROM [tblOvrdImpVols] WHERE ([key1] = 9898) AND ([key2] is null)
    --returns 1 row

select * FROM [tblOvrdImpVols] WHERE ([key1] = 9898) AND ([key2] = null)
    --returns 0 rows

我假设,如果我能让 DataContext 对象将 = 替换为 is 以处理 null 值,删除操作就会成功。但我不知道如何实现。我认为这个问题以前已经被问过,但我找不到相关信息。
编辑:我最初将我的键称为“主键”,而非“外键”。我本意是说“外键”。我已经编辑了我的帖子,用“外键”代替了“主键”。但我仍然遇到同样的问题。

3
据我所知,SQL Server 不允许主键的任何列为空。我不知道你是如何让它运行起来的 - 我认为这基本上根本不可能做到.... - marc_s
更不用说这样做完全是疯狂的尝试。 - Grant Thomas
糟糕,我本来想说外键。在我的代码中,key1key2都是外键,而不是主键。这是我的错误。 - user2023861
我认为你的数据库模型可能有问题,Key1和Key2应该被标记为IsPrimaryKey属性。 - sgmoore
我不小心打错了“主键”而本来想打“外键”。昨天我编辑了我的帖子以修复这个错误。Key1Key2都没有标记为IsPrimaryKey属性。这不是关于数据库模型的问题,而是关于在其中一个列为空时删除行的问题。 - user2023861
显示剩余2条评论
2个回答

0
主要问题在于 SQL 中,没有任何东西等于 NULL。即使是 NULL 本身也不相等!在 SQL 查询中,“NULL = NULL” 将评估为“false”。因此,当您需要删除 [key2] == null 的行时,您需要编写 LINQ 查询,该查询将生成类似于
"WHERE [key2] = @p1 AND [key2] IS NULL"
而不是
"WHERE [key2] = @p1 AND [key2] = @p2" 的 SQL。
如何做到这一点?似乎正确的方法是将 [key2] 与 null 进行比较。例如,如果您想从 tblSecurityMasterType 获取所有 Name 为 NULL 的行,则以下方法是错误的:
string NameNull = null;
from sm in db.tblSecurityMasterType 
     where sm.Name == NameNull
     select sm;

你需要使用这个查询:

from sm in db.tblSecurityMasterType 
     where sm.Name == null
     select sm;

这里有描述:http://smsohan.com/blog/2008/08/05/comparing-with-null-in-where-clause-in/

0
为了确保你也能捕获到空值,你可以修改查询语句如下:
select * FROM [tblOvrdImpVols] 
WHERE ([key1] = @p0) AND 
([key2] = @p1 OR 
    ([key2] is null and @p1 is null) )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接