LINQ to SQL查询基于使用外键与使用内置导航属性成功或失败

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LINQ to SQL查询基于使用外键与使用内置导航属性成功或失败相关的知识,希望对你有一定的参考价值。

我有一个SQL服务器数据库的查询,抛出一个Error converting data type nvarchar to numeric.异常。我试图在varchar字段上使用Convert.ToDecimal,但是我会尽可能地对数据进行观察,并且找不到无效值。

该查询使用p.pgKey=#的外键通过'Group'过滤表。但是,如果我使用导航属性并通过导航属性过滤,p.Group.gName='ABC'查询工作。

以下是查询(请注意,最初,我不知道是否在Where翻译或Select处理中发生错误,所以这就是为什么查询看起来很奇怪,但正如你可以猜到的,当它工作时,它应该只返回一个独特的true行):

Profiles
    .Where(p =>
       p.pgKey == 237
       && !p.pPlanProfile.Value
      && Convert.ToDecimal(p.pSearch08 ?? "0") > 0
    ).Select(p =>
       Convert.ToDecimal(p.pSearch08 ?? "0") > 0
    )
    .Distinct()
    .Dump();

上述查询失败,而此查询成功:

Profiles
    .Where(p =>
       p.Groups.gName == "ABC"
       && !p.pPlanProfile.Value
       && Convert.ToDecimal(p.pSearch08 ?? "0") > 0
    ).Select(p =>
       Convert.ToDecimal(p.pSearch08 ?? "0") > 0
    )
    .Distinct()
    .Dump();

下面是一个完整的LINQPad屏幕转储显示:

  1. 证明ABC的gKey是237。
  2. 证明使用pgKeyGroup.gName时计算Profile记录的简单计数是相同的。
  3. 使用Group.gName处理时显示查询正常工作。
  4. 使用pgKey处理时显示查询失败。

LINQPad screenshot

显然我已经使用Group.gName方法来解决我的问题,但我偶然发现了这个解决方案。任何人都知道为什么LINQ to SQL会以这种方式运行?

注意:我使用LINQPad生成的DataContext或者针对编译的.dbml DataContext运行时获得相同的行为。

答案

这两个查询将生成不同的TSQL,因此查询计划将有所不同。

我怀疑前一个查询是在尝试将pSearch08的某些值转换为十进制,然后根据其他选择标准拒绝它们,而后一个查询首先执行其他选择条件,因此尝试转换较少数量的pSearch08值为十进制,因此不会尝试转换无效值。

如果是这种情况,那么假设第二个查询将始终有效并且最好修复无效数据可能是危险的。

您可以尝试而不是关注数据

SELECT * from Profile where ISNUMERIC(pSearch08) = 0

以上是关于LINQ to SQL查询基于使用外键与使用内置导航属性成功或失败的主要内容,如果未能解决你的问题,请参考以下文章

使用内置 Linq to SQL 驱动程序在 LinqPad 中运行 Entity Framework Core 查询的更简单方法?

C# Linq 将外键与内键反转为以字典为值的字典

sql用命令创建主键与外键。

SQL Server:主键与外键设置与相关理解

LINQ to SQL和外键的基本误解

使用 ASP.NET 动态数据/LINQ to SQL,如何让两个表字段与同一个外键有关系?