2016-09-15 7 views
0

Если у меня есть инструкция по обновлению, такая как update foo set bar = @bar, baz = @baz, и создайте команду, в которой отсутствуют параметры, похоже, что обновление будет использовать текущие значения для этих столбцов.Поведение по умолчанию по умолчанию Npgsql

Я не смог найти документацию для этого в 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(); 
     } 
    } 
} 

ответ

1

Это действительно немного странно, вот что происходит.

PostgreSQL принимает помещики позиционных параметров в формате $ 1, $ 2 и т. Д. Однако в .NET это стандартно, так как они имеют имена заполнителей, например. @bar, @baz. Чтобы поддержать это, Npgsql анализирует вашу клиентскую сторону SQL, чтобы найти любые заполнители параметров (например, @bar). Когда он найден, он ищет NpgsqlParameter с соответствующим именем в NpgsqlCommand и заменяет его совместимым с PostgreSQL позиционным заполнителем (например, $ 1).

Теперь, если Npgsql встречается с заполнителем без соответствующего NpgsqlParameter, он просто оставляет его в покое. В какой-то момент он выбрал исключение, но были некоторые случаи, когда внутренний анализатор SQL Npgsql был недостаточно хорош и неправильно идентифицировал части запроса в качестве заполнитель параметров. Оставляя идентифицированные заполнители, которые не имеют соответствующего NpgsqlParameter, решает эту проблему.

Все это для того, чтобы сказать, что ваш PostgreSQL получает литерал SQL update foo set bar = @bar, baz = @baz без каких-либо манипуляций со стороны Npgsql. Теперь PostgreSQL рассматривает @ как специальный символ - вы можете определить его как оператор (см. https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html). Однако по умолчанию @ ничего не делает, поэтому на самом деле вы сделали update foo set bar = bar, baz = baz, что явно ничего не делает. Вы можете увидеть поведение @, выполнив SELECT @foo. PostgreSQL ответит сообщением column "foo" does not exist.

Так что это взаимодействие между Npgsql, оставляющим запрос as-is, потому что параметр не установлен, а PostgreSQL игнорирует @.

 Смежные вопросы

  • Нет связанных вопросов^_^