C# 尝试在DynamicParameter中传递null时,Dapper报告参数名称附近的无效语法

C# 尝试在DynamicParameter中传递null时,Dapper报告参数名称附近的无效语法,c#,sql-server,dapper,C#,Sql Server,Dapper,我试图从某个字段不是空字符串或null的表中获取所有记录。由于我构建查询的方式,ISNULL和COALESCE不是这里的选项。更改数据库的架构也不是一个选项 这是我试图检索记录的代码 using System; using System.Data.SqlClient; using System.Linq; using Dapper; namespace DapperMCVE { internal class UserFinder { public static

我试图从某个字段不是空字符串或null的表中获取所有记录。由于我构建查询的方式,
ISNULL
COALESCE
不是这里的选项。更改数据库的架构也不是一个选项

这是我试图检索记录的代码

using System;
using System.Data.SqlClient;
using System.Linq;
using Dapper;

namespace DapperMCVE
{
    internal class UserFinder
    {
        public static void Main(string[] args)
        {
            using (var connection = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;Integrated Security=True"))
            {
                connection.Execute(@"IF NOT EXISTS(SELECT * FROM sys.tables WHERE name = 'Users')
                                        CREATE TABLE Users(NullableUserId varchar(50) NULL) ON [PRIMARY]");
                connection.Execute(@"DELETE Users");
                connection.Execute(@"INSERT INTO Users(NullableUserId) 
                                     VALUES(''), (NULL), ('SteveSmith@fake.com'), ('Morgan@totallyreal.org')");
                var parameters = new DynamicParameters();
                parameters.Add("UserIdNull", (string)null);
                parameters.Add("UserIdBlank", "");
                try
                {
                    var users = connection.Query(@"SELECT * 
                                                   FROM Users 
                                                   WHERE NullableUserId IS NOT @UserIdNull 
                                                     AND NullableUserId != @UserIdBlank", parameters);
                    Console.WriteLine(users.ToList());
                }
                catch (SqlException e)
                {
                    Console.WriteLine(e);
                }
                Console.ReadKey();
            }
        }
    }
}
引发的错误是
System.Data.SqlClient.SqlException(0x80131904)“@UserIdNull”附近的语法不正确。

我的假设是上述代码应该复制此查询:

SELECT *
  FROM Users
  WHERE NullableUserId IS NOT NULL
    AND NullableUserId != ''
但它似乎在做一些更接近于

SELECT *
FROM Users
WHERE NullableUserId IS NOT 'NULL'
  AND NullableUserId != ''
如果我将查询更改为

SELECT *
FROM Users
WHERE ISNULL(NullableUserId, '') != ISNULL(@UserIdNull, '')
它很好用。不幸的是,在这种情况下,我不能使用
ISNULL

我在SQL Server 2014和2016中复制了这一点。我们在生产环境中使用2016

探查器报告正在运行以下命令:

exec sp_executesql N'SELECT * 
                     FROM Users 
                     WHERE NullableUserId IS NOT @UserIdNull 
                       AND NullableUserId != @UserIdBlank',N'@UserIdNull nvarchar(4000),@UserIdBlank nvarchar(4000)',@UserIdNull=NULL,@UserIdBlank=N''
这让我怀疑这可能是SQL Server本身的问题

我尝试过的事情(无效):


您不能使用的是not和variable。如果总是希望为NULL,则可以硬编码NullableUserId不为NULL。
或者使用一些字符串连接创建查询文本

您不能在sp_executesql或其他任何地方使用
IS NOT
和参数。
看看这个例子

此查询从我的表中返回4条记录:

exec sp_executesql 
N'SELECT * FROM tblUser WHERE gsm IS NOT null AND gsm != '''''
所以现在我尝试使用这两个值的参数,现在我得到一个错误

exec sp_executesql 
N'SELECT * FROM tblUser WHERE gsm IS NOT @UserIdNull AND gsm <> @UserIdBlank',
N'@UserIdNull nvarchar(100),@UserIdBlank nvarchar(100)',
@UserIdNull=NULL,@UserIdBlank=N''
exec sp_executesql
N‘从tblUser中选择*,其中gsm不是@UserIdNull和gsm@UserIdBlank’,
N'@UserIdNull nvarchar(100),@UserIdBlank nvarchar(100)',
@UserIdNull=NULL,@UserIdBlank=N''
但现在我得到了错误

“@UserIdNull”附近的语法不正确

如果不使用sp_executesql执行此操作,则会出现相同的错误

declare @UserIdNull nvarchar(100) = null
declare @UserIdBlank nvarchar(100) = ''
SELECT * FROM tblUser WHERE gsm IS NOT @UserIdNull AND gsm <> @UserIdBlank
declare@UserIdNull-nvarchar(100)=null
声明@UserIdBlank nvarchar(100)=”
从tblUser中选择*,其中gsm不是@UserIdNull和gsm@UserIdBlank
这会产生相同的错误

因此,您唯一的选择是为
is NOT
值或使用
ISNULL()

在您在问题中构建的查询中,您知道何时写入
不是
,然后后跟一个参数。

我建议简单地编写
IS NOT NULL
而不是在那里使用参数

IS NOT@UserIdNull
实际上是无效的SQL语法<代码>不为空可以。这不是一个简单的问题——这只是一个SQL特性:您需要编写合法的SQL

我的假设是上述代码应该复制此查询:

SELECT *
  FROM Users
  WHERE NullableUserId IS NOT NULL
    AND NullableUserId != ''

没有。它使用参数。保留语法。Dapper不注入文本。这是非常慎重和正确的,正如它发生的那样。

那么,为什么不使用探查器捕获实际的sql命令呢?我不知道是否简洁,但可能在
parameters.Add中(“UserIdNull”,(string)null)
您应该以某种方式使用DBNull.Value?@GuidoG我从分析器中添加了命令。我提供的第二个链接地址是
DBNull.Value
。tl;dr是dapper不支持它,因为他们希望您使用
null
。为什么在这种情况下不能使用isnull()?@GuidoG我正在根据传递给我的JSON对象动态构建整个查询。我无法提前知道该字段是否可以为空,如果可以,相应的默认值是什么。话虽如此,我可能会修改API以允许这样做,但我希望找到一种解决方案,允许Dapper对空值进行过滤。问题是我事先不知道字段是否可以为空。用户正在传递操作员,在这种情况下,
不是
。即使我知道字段是可空的,我也不知道
ISNULL
的默认值应该是什么。我明白了,但是当你得到操作符
不是
时,你能不能不总是在它后面写
NULL
,而不是一个参数?不,因为
不是
可能是
不在
的一部分,是的,你是对的。恐怕我已经没有选择了,我们不应该期望这里显示的代码(在这个答案中)能够正常工作。
sp_executesql
的全部要点——它存在的原因——是允许动态SQL使用参数;参数从不被注入-它们作为参数保留。这在
sp_executesql
中不是问题-这是正确的行为。我强烈建议您浏览一下有趣的网站。我不知道SQL中不支持这一点。