Подтвердить что ты не робот

Использование 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()!!!!! Мне стыдно это сказать, но там у вас есть.

Я до сих пор не знаю, что происходит с синтаксисом, который я получаю от профилировщика. Сотрудник наблюдал со своим экземпляром профилировщика со своего компьютера, и он возвращал правильный синтаксис. Наблюдение за самыми САМАМИ исполнениями из моего профилировщика показало неправильный синтаксис. Он действовал как красная селедка, заставляя меня поверить, что была проблема синтаксиса запроса, а не намного более простой и верный ответ, который заключался в том, что мне нужно совершить транзакцию!

Я отметил ответ ниже как правильный и бросил несколько голосов на других, потому что они, в конце концов, ответили на вопрос, даже если они не исправили мою конкретную проблему (провал мозга).

4b9b3361

Ответ 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())