c# - sql parameter date
Usar DateTime en un SqlParameter para el procedimiento almacenado, formatear el error (4)
Estoy intentando llamar a un procedimiento almacenado (en un servidor SQL 2005) desde C #, .NET 2.0 usando DateTime
como un valor para un SqlParameter
. El tipo de SQL en el procedimiento almacenado es ''datetime''.
Ejecutar el sproc de SQL Management Studio funciona bien. Pero cada vez que lo llamo desde C # me sale un error sobre el formato de fecha.
Cuando ejecuto SQL Profiler para ver las llamadas, copio y pego la llamada del exec
para ver qué está pasando. Estas son mis observaciones y notas sobre lo que he intentado:
1) Si paso el DateTime
directamente como DateTime
o lo convierto a SqlDateTime
, el campo estará rodeado por un par de comillas simples, como
@Date_Of_Birth=N''''1/8/2009 8:06:17 PM''''
2) Si paso el DateTime
como una cadena, solo obtengo las comillas simples
3) El uso de SqlDateTime.ToSqlString()
no da como resultado una cadena de fecha y hora formateada en UTC (incluso después de convertirla en hora universal)
4) El uso de DateTime.ToString()
no da como resultado una cadena de fecha y hora formateada en UTC.
5) Configurar manualmente el DbType
para el SqlParameter
a DateTime
no cambia las observaciones anteriores.
Entonces, mi pregunta es, ¿cómo diablos puedo obtener C # para pasar el tiempo adecuadamente formateado en el SqlParameter
? Sin duda, este es un caso de uso común, ¿por qué es tan difícil trabajar? Parece que no puedo convertir DateTime
en una cadena que sea compatible con SQL (p. Ej., ''2009-01-08T08: 22: 45'')
EDITAR
RE: BFree, el código para ejecutar realmente el sproc es el siguiente:
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();
}
Para entrar en más detalles sobre lo que he intentado:
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 adicional
El que creí más probable que funcionara:
SqlParameter param = new SqlParameter("@Date_Of_Birth",
System.Data.SqlDbType.DateTime);
param.Value = DOB;
Resultados en este valor en la llamada ejecutiva como se ve en el Analizador de SQL
@Date_Of_Birth=''''2009-01-08 15:08:21:813''''
Si modifico esto para ser:
@Date_Of_Birth=''2009-01-08T15:08:21''
Funciona, pero no analizará con un par de comillas simples, y no se convertirá a DateTime
correctamente con el espacio entre la fecha y la hora y con los milisegundos al final.
Actualización y éxito
Copié / pegué el código anterior después de la solicitud de abajo. Recorté las cosas aquí y allá para ser conciso. Resulta que mi problema estaba en el código que dejé, y estoy seguro de que cualquiera de ustedes lo habría visto en un instante. Envolví mis llamadas sproc dentro de una transacción. Resulta que simplemente no estaba haciendo transaction.Commit()
!!!!! Me da vergüenza decirlo, pero ahí lo tienes.
Todavía no sé qué está pasando con la sintaxis que obtengo del generador de perfiles. Un compañero de trabajo observó con su propia instancia del generador de perfiles de su computadora y devolvió la sintaxis adecuada. Ver las MISMAS ejecuciones de mi generador de perfiles mostró la sintaxis incorrecta. Actuó como un pretexto, haciéndome creer que había un problema de sintaxis de consulta en lugar de la respuesta mucho más simple y verdadera, ¡que era que tenía que comprometer la transacción!
Marqué una respuesta a continuación como correcta y agregué algunos votos positivos a otros porque, después de todo, respondieron la pregunta, incluso si no solucionaron mi problema específico (lapso cerebro).
¿Cómo está configurando el SqlParameter
? Debe establecer la propiedad SqlDbType
en SqlDbType.DateTime
y luego pasar el DateTime
directamente al parámetro (NO convertir a una cadena, entonces está pidiendo un montón de problemas).
Debería poder obtener el valor en la base de datos. Si no, aquí hay un ejemplo muy simple de cómo hacerlo:
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();
}
}
}
Creo que parte del problema aquí es que le preocupa que el hecho de que la hora esté en UTC no se transmita a SQL Server. Con ese fin, no debe hacerlo, porque SQL Server no sabe que una hora en particular se encuentra en una zona / zona horaria en particular.
Si desea almacenar el valor UTC, conviértalo a UTC antes de pasarlo a SQL Server (a menos que su servidor tenga el mismo huso horario que el código cliente que genera el DateTime
, e incluso entonces, eso es un riesgo, IMO). SQL Server almacenará este valor y cuando lo recupere, si desea mostrarlo en la hora local, debe hacerlo usted mismo (lo que la estructura DateTime
hará fácilmente).
Dicho todo esto, si realiza la conversión y luego pasa la fecha UTC convertida (la fecha que se obtiene llamando al método ToUniversalTime
, no mediante la conversión a una cadena) al procedimiento almacenado.
Y cuando recupere el valor, llame al método ToLocalTime
para obtener la hora en la zona horaria local.
Aquí es cómo agrego parámetros:
sprocCommand.Parameters.Add(New SqlParameter("@Date_Of_Birth",Data.SqlDbType.DateTime))
sprocCommand.Parameters("@Date_Of_Birth").Value = DOB
Supongo que cuando escribes DOB no hay citas.
¿Estás usando un control de terceros para obtener la fecha? He tenido problemas con la forma en que se genera el valor de texto de algunos de ellos.
Por último, ¿funciona si escribe el atributo .Value del parámetro sin hacer referencia a DOB?
Si usa Microsoft.ApplicationBlocks.Data
hará que llamar a sus sprocs sea una sola línea
SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB)
Ah, y creo que CasperOne es correcto ... si quieres asegurarte de la fecha y hora correcta en varias zonas horarias, simplemente conviértela en UTC antes de enviar el valor a SQL Server.
SqlHelper.ExecuteNonQuery(ConnectionString, "SprocName", DOB.ToUniversalTime())
Solo usa:
param.AddWithValue("@Date_Of_Birth",DOB);
Eso se encargará de todos tus problemas.