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

时间:2017-12-07 14:41:27

标签: c# sql-server dapper

我试图从某个表中获取所有记录,其中某个字段不是空字符串或null。由于我构建查询的方式,ISNULLCOALESCE不是此处的选项。也不能选择更改数据库的模式。

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

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): Incorrect syntax near '@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本身的一个问题?

我尝试过的事情(无济于事):

3 个答案:

答案 0 :(得分:3)

您不能使用IS NOT和变量。如果你总是期望null,你可以硬编码NullableUserId IS NOT NULL。 或者使用一些字符串连接创建查询文本

答案 1 :(得分:2)

您不能在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''

但现在我收到了错误

  

'@ UserIdNull'附近的语法不正确

在没有sp_executesql的情况下执行此操作时会出现相同的错误

declare @UserIdNull nvarchar(100) = null
declare @UserIdBlank nvarchar(100) = ''
SELECT * FROM tblUser WHERE gsm IS NOT @UserIdNull AND gsm <> @UserIdBlank

这会产生相同的错误

因此,唯一的选择是在没有IS NOT值参数的情况下构建查询或使用ISNULL()

在您构建问题的查询中,您知道何时编写IS NOT,然后写入参数。
我建议只需编写IS NOT NULL而不是使用参数

答案 2 :(得分:2)

IS NOT @UserIdNull真的不是有效的SQL语法.... IS NOT NULL没问题。这不是一个小巧的问题 - 这只是一个SQL功能:你需要编写合法的SQL。

  

我的假设是上面的代码应该复制这个查询:

不。它使用参数。语法被保留。 Dapper不会注入文字。这是非常慎重和正确的。 I wrote about this yesterday,正好相反。