Использование DateTime в SqlParameter для хранимой процедуры, форматирование ошибки
Я пытаюсь вызвать хранимую процедуру (на сервере SQL 2005) из С#,.NET 2.0, используя DateTime
как значение для SqlParameter
. Тип SQL в хранимой процедуре - это "datetime".
Выполнение sproc из SQL Management Studio отлично работает. Но каждый раз, когда я вызываю его из С#, я получаю сообщение об ошибке формата даты.
Когда я запускаю SQL Profiler для просмотра вызовов, я затем копирую вставьте вызов exec
, чтобы узнать, что происходит. Это мои наблюдения и заметки о том, что я пытался:
1) Если я передаю DateTime
непосредственно как DateTime
или преобразован в SqlDateTime
, поле окружает PAIR одинарных кавычек, например
@Date_Of_Birth=N''1/8/2009 8:06:17 PM''
2) Если я передаю DateTime
в качестве строки, я получаю только одиночные кавычки
3) Использование SqlDateTime.ToSqlString()
не приводит к форматированной в формате UTC строке даты (даже после преобразования в универсальное время)
4) Использование DateTime.ToString()
не приводит к строкой datetime в формате UTC.
5) Ввод вручную DbType
для SqlParameter
в DateTime
не изменит приведенные выше наблюдения.
Итак, теперь мои вопросы: каким образом я получаю С#, чтобы передать правильно отформатированное время в SqlParameter
? Конечно, это распространенный случай использования, почему так сложно работать? Я не могу преобразовать DateTime
в строку, совместимую с SQL (например, "2009-01-08T08: 22: 45 ')
ИЗМЕНИТЬ
RE: BFree, код для фактического выполнения sproc выглядит следующим образом:
using (SqlCommand sprocCommand = new SqlCommand(sprocName))
{
sprocCommand.Connection = transaction.Connection;
sprocCommand.Transaction = transaction;
sprocCommand.CommandType = System.Data.CommandType.StoredProcedure;
sprocCommand.Parameters.AddRange(parameters.ToArray());
sprocCommand.ExecuteNonQuery();
}
Более подробно о том, что я пробовал:
parameters.Add(new SqlParameter("@Date_Of_Birth", DOB));
parameters.Add(new SqlParameter("@Date_Of_Birth", DOB.ToUniversalTime()));
parameters.Add(new SqlParameter("@Date_Of_Birth",
DOB.ToUniversalTime().ToString()));
SqlParameter param = new SqlParameter("@Date_Of_Birth",
System.Data.SqlDbType.DateTime);
param.Value = DOB.ToUniversalTime();
parameters.Add(param);
SqlParameter param = new SqlParameter("@Date_Of_Birth",
SqlDbType.DateTime);
param.Value = new SqlDateTime(DOB.ToUniversalTime());
parameters.Add(param);
parameters.Add(new SqlParameter("@Date_Of_Birth",
new SqlDateTime(DOB.ToUniversalTime()).ToSqlString()));
Дополнительный EDIT
Тот, который, как я думал, скорее всего будет работать:
SqlParameter param = new SqlParameter("@Date_Of_Birth",
System.Data.SqlDbType.DateTime);
param.Value = DOB;
Результаты этого значения в вызове exec, как показано в SQL Profiler
@Date_Of_Birth=''2009-01-08 15:08:21:813''
Если я изменяю это как:
@Date_Of_Birth='2009-01-08T15:08:21'
Он работает, но он не будет анализировать пару одиночных кавычек, и он не будет правильно преобразовывать в DateTime
с промежутком между датой и временем и с миллисекундами в конце.
Обновление и успех
У меня был экземпляр/вставил код выше после запроса снизу. Я урезал вещи здесь и там, чтобы быть кратким. Оказывается, моя проблема была в коде, который я забыл, и я уверен, что кто-то из вас заметил бы в одно мгновение. Я заключил свои звонки в транзакции. Оказывается, я просто не делал transaction.Commit()
!!!!! Мне стыдно это сказать, но там у вас есть.
Я до сих пор не знаю, что происходит с синтаксисом, который я получаю от профилировщика. Сотрудник наблюдал со своим экземпляром профилировщика со своего компьютера, и он возвращал правильный синтаксис. Наблюдение за самыми САМАМИ исполнениями из моего профилировщика показало неправильный синтаксис. Он действовал как красная селедка, заставляя меня поверить, что была проблема синтаксиса запроса, а не намного более простой и верный ответ, который заключался в том, что мне нужно совершить транзакцию!
Я отметил ответ ниже как правильный и бросил несколько голосов на других, потому что они, в конце концов, ответили на вопрос, даже если они не исправили мою конкретную проблему (провал мозга).
Ответы
Ответ 1
Как вы настраиваете SqlParameter
? Вы должны установить свойство SqlDbType
в SqlDbType.DateTime
а затем передайте DateTime
непосредственно к параметру (НЕ конвертируйте в строку, вы просите о проблемах).
Вы должны иметь возможность получить значение в БД. Если нет, вот очень простой пример того, как это сделать:
static void Main(string[] args)
{
// Create the connection.
using (SqlConnection connection = new SqlConnection(@"Data Source=..."))
{
// Open the connection.
connection.Open();
// Create the command.
using (SqlCommand command = new SqlCommand("xsp_Test", connection))
{
// Set the command type.
command.CommandType = System.Data.CommandType.StoredProcedure;
// Add the parameter.
SqlParameter parameter = command.Parameters.Add("@dt",
System.Data.SqlDbType.DateTime);
// Set the value.
parameter.Value = DateTime.Now;
// Make the call.
command.ExecuteNonQuery();
}
}
}
Я думаю, что часть проблемы здесь состоит в том, что вы обеспокоены тем, что тот факт, что время в UTC не передается SQL Server. С этой целью вы не должны, потому что SQL Server не знает, что определенное время находится в определенной локали/часовом поясе.
Если вы хотите сохранить значение UTC, а затем преобразовать его в UTC, прежде чем передавать его на SQL Server (если ваш сервер не имеет тот же часовой пояс, что и клиентский код, генерирующий DateTime
, и даже тогда, ИМО). SQL Server сохранит это значение, и когда вы его вернете, если вы хотите отобразить его в локальное время, вы должны сделать это самостоятельно (что легко может создать структура DateTime
).
Все сказанное, если вы выполняете преобразование, а затем передаете преобразованную дату UTC (дату, полученную вызовом метода ToUniversalTime
, а не путем преобразования в строку) в хранимую процедуру.
И когда вы вернете это значение, вызовите метод ToLocalTime
, чтобы получить время в локальном часовом поясе.
Ответ 2
Вот как я добавляю параметры:
sprocCommand.Parameters.Add(New SqlParameter("@Date_Of_Birth",Data.SqlDbType.DateTime))
sprocCommand.Parameters("@Date_Of_Birth").Value = DOB
Я предполагаю, что когда вы выписываете DOB, нет кавычек.
Используете ли вы сторонний элемент управления для получения даты? У меня были проблемы с тем, как генерируется текстовое значение из некоторых из них.
Наконец, он работает, если вы вводите атрибут .Value параметра без ссылки на DOB?
Ответ 3
Просто используйте:
param.AddWithValue("@Date_Of_Birth",DOB);
Это позаботится обо всех ваших проблемах.
Ответ 4
Если вы используете Microsoft.ApplicationBlocks.Data
, он вызовет ваши sprocs в одной строке
SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB)
О, и я думаю, что casperOne прав... если вы хотите обеспечить правильное время и время за несколько часовых поясов, тогда просто преобразуйте значение в UTC, прежде чем отправлять значение SQL Server
SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB.ToUniversalTime())