如果我有update foo set bar = @bar, baz = @baz
之类的更新语句,并创建一个缺少参数的命令,则看起来更新将使用这些列的当前值。
我还没有能够在Npgsql或Postgresql中找到相关文档 - 它是一个支持的功能,而不是我可以依赖的,或只是发生了什么?
琐碎的例子:
using System;
using Npgsql;
namespace MissingParametersUpdate
{
static class Program
{
// you will need to have CREATE TABLE foo ( bar integer, baz integer )
static void Main(string[] args)
{
using (var connection = new NpgsqlConnection(args[0]))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"delete from foo";
command.ExecuteNonQuery();
}
using (var command = connection.CreateCommand())
{
command.CommandText = @"insert into foo ( bar, baz ) values ( 1, 2 ), (3, 4)";
command.ExecuteNonQuery();
}
DumpValues("Initial", connection);
// empty update
using (var command = connection.CreateCommand())
{
command.CommandText = @"update foo set bar = @bar, baz = @baz";
command.ExecuteNonQuery();
}
DumpValues("Empty Update", connection);
// update bar
using (var command = connection.CreateCommand())
{
command.CommandText = @"update foo set bar = @bar, baz = @baz";
command.Parameters.AddWithValue(@"bar", 42);
command.ExecuteNonQuery();
}
DumpValues("Update Bar", connection);
// update baz
using (var command = connection.CreateCommand())
{
command.CommandText = @"update foo set bar = @bar, baz = @baz";
command.Parameters.AddWithValue(@"baz", 12);
command.ExecuteNonQuery();
}
DumpValues("Update Baz", connection);
}
}
private static void DumpValues(string caption, NpgsqlConnection connection)
{
Console.WriteLine(caption);
using (var command = connection.CreateCommand())
{
command.CommandText = @"select bar, baz from foo";
using (var reader = command.ExecuteReader())
while (reader.Read())
Console.WriteLine(" (bar: {0}, baz: {1})", reader.GetInt32(0), reader.GetInt32(1));
}
Console.WriteLine();
}
}
}
答案 0 :(得分:1)
这确实有点奇怪,这里发生了什么。
PostgreSQL接受格式为$ 1,$ 2等的位置参数占位符。但是,在.NET中有一些标准的占位符,例如@bar,@ baz。为了支持这一点,Npgsql解析您的SQL客户端以查找任何参数占位符(例如@bar
)。当找到一个时,它会在NpgsqlCommand上查找带有相应名称的NpgsqlParameter,并将其替换为与PostgreSQL兼容的位置占位符(例如$ 1)。
现在,如果Npgsql在没有相应的NpgsqlParameter的情况下遇到占位符,它就会单独留下它。它在某些时候引发了异常,但在某些情况下,Npgsql的内部SQL解析器不够好,并且错误地将查询的部分标识为参数占位符。留下没有相应NpgsqlParameter的已识别占位符可以解决此问题。
所有这些都表明你的PostgreSQL收到了文字SQL update foo set bar = @bar, baz = @baz
,而没有对Npgsql的任何操作。现在,PostgreSQL将@视为特殊字符 - 您可以将其定义为运算符(请参阅https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html)。但是,默认情况下,@ doesn似乎根本没有做任何事情,所以你实际做的是运行update foo set bar = bar, baz = baz
,这显然什么都不做。您可以通过执行SELECT @foo
来查看@行为 - PostgreSQL将回复错误column "foo" does not exist
。
所以它是Npgsql之间的相互作用,因为参数没有设置,而且PostgreSQL忽略了@。