2012-04-24 22 views
6

Existen varias preguntas sobre el uso de .Net DateTime en las sentencias Sql, pero ninguna de ellas resolvió mi problema.Forma correcta de utilizar .Net DateTime en cadena SQL parametrizada

estoy usando el siguiente código para consultar una base de datos Oracle:

private DataTable QueryByIdAndDate(string id, DateTime fdate, DateTime tdate) { 
    string query = "SELECT * FROM table WHERE ID = :id AND DATE_TIME BETWEEN :from AND :to" 
    DbCommand cmd = db.CreateCommand(); 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandText = query; 

    DbParameter fromDate = CreateDateParameter(cmd, fdate); 
    fromDate.ParameterName = "from"; 
    DbParameter toDate = CreateDateParameter(cmd, tdate); 
    toDate.ParameterName = "to"; 
    DbParameter idParam = CreateStringParameter(cmd, id); 
    idParam.ParameterName = "id"; 

    cmd.Parameters.AddRange(new DbParameter[] { fromDate, toDate, idParam }); 
    return db.ExecuteQuery(cmd); 
} 

private DbParameter CreateDateParameter(DbCommand cmd, DateTime date) { 
    DbParameter param = cmd.CreateParameter(); 
    param.DbType = DbType.DateTime; 
    param.Direction = ParameterDirection.Input; 
    param.Value = date; 
    return param; 
} 

Pero no funciona correctamente. Al tratar el código a cabo de esta manera:

DataTable result = QueryByIdAndDate("12345", DateTime.Now, DateTime.Now.AddDays(1)); 

Se da el siguiente error: ORA-01847 : día del mes debe estar entre 1 y último día del mes

Estoy asumiendo que tiene que ver con la forma en que DateTime está formateado, pero no sé la manera correcta de solucionarlo de manera confiable.

+0

No estaría ejecutándolo por 30 de mes con solo 30 días, ¿verdad? –

+0

No. Falló con el ejemplo que mostré usando DateTime.Now y DateTime.Now.AddDays (1); – user12345613

+2

¿Su controlador definitivamente soporta parámetros con nombre? Si está tratando de usarlos por posición, terminará usando el valor "id" como la parte "a", que podría romperse. ¿Qué conductor estás usando? –

Respuesta

10

(De acuerdo con los comentarios ...)

Parece que en este caso, el orden de los parámetros asuntos ... a pesar de que usted les ha dado nombres. No hubiera esperado esto, y es el signo de un conductor de un poco roto, pero cambiando el código para:

cmd.Parameters.AddRange(new DbParameter[] { idParam, fromDate, toDate }); 

debe solucionarlo. (Esto no es necesariamente la forma en que debería estar construyendo sus parámetros, por cierto, pero eso es un tanto irrelevante aquí.)

Haz no inicio especificando los valores de fecha/hora como cadenas. Es una muy mala idea para introducir más conversiones de cadenas de las que necesita.

+0

Sí, ni siquiera pensé en el orden de esa matriz (que era tonto) ya que son parámetros nombrados. Además, estoy abierto a cualquier comentario o sugerencia sobre la construcción adecuada de los parámetros. – user12345613

+0

En mi experiencia, hay muchas cosas rotas en los controladores .NET de oracle, incluido el orden de los parámetros o la necesidad de cambiar las sentencias de SQL para eliminar las excepciones de referencia NULL. –

+0

@ user12345613: No puedo decir que sea un área con la que tengo mucha experiencia, pero si usa la colección de parámetros de comandos fuertemente tipados, es probable que obtenga opciones como 'AddWithValue' que hacen la vida más fácil. –

3

convertir el valor DateTime a una cadena de fecha con formato:

private DbParameter CreateDateParameter(DbCommand cmd, DateTime date) 
{ 
    DbParameter param = cmd.CreateParameter(); 
    param.DbType = DbType.DateTime; 
    param.Direction = ParameterDirection.Input; 
    param.Value = date.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); 
    return param; 
} 

A pesar de que va a enviar un valor de cadena, el DbType está siendo ajustado a DateTime, por lo que el valor debe se convierten correctamente.

+0

Tenga en cuenta que incluso si este fuera realmente el problema, probablemente quiera usar la cultura invariante, y definitivamente querría cambiar "hh" a " S.S". Sin embargo, recomendaría encarecidamente * en contra de * realizar dichas conversiones. –

+0

Nada se obtiene por @JonSkeet. De acuerdo, salté directamente al problema de formato y nunca consideré el orden de los parámetros. Actualizado según sus sugerencias. – mgnoonan

2

Oracle espera las fechas formateadas como 'DD-Mon-YYYY', por lo que básicamente necesita formatear el valor de su fecha y asignarlo al valor del parámetro.

Editar: Me he dado cuenta de que las versiones recientes de ODP parecen manejar mejor los parámetros de fecha y hora. Por ejemplo, esto funciona bien cuando hay una restricción en una cláusula WHERE en una columna de fecha/hora:

DateTime dt = new DateTime(2012, 5, 21); 
cmd.Parameters.Add("some_date_param", dt); 

Ejecución de una consulta de esta manera con la última versión del PAO funciona bien. Pero tengo un montón de código donde los valores de fecha/hora deben pasarse como cadenas formateadas para que Oracle los acepte.

1

Para aquellos que podrían perder, ver el comentario de @kprobst bajo la respuesta aceptada por @JonSkeet:

No importa lo bien que formatea los valores de los parámetros, etc, si usted está tratando de utilizar nombre vinculante sin establecer la propiedad BindByName en el Command.

(Toda la API del proveedor de Oracle es un montón de basura en mi humilde opinión).

Cuestiones relacionadas