2012-04-24 10 views
6

Es gibt einige Fragen über die Verwendung von. Net DateTime in Sql-Anweisungen, aber keiner von ihnen löste mein Problem.Proper Weg zu verwenden. Net DateTime in parametrisierten SQL-Zeichenfolge

Ich verwende den folgenden Code, um eine Oracle-Datenbank abzufragen:

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; 
} 

Aber es funktioniert nicht richtig. Wenn der Code versucht, so wie aus:

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

Es gibt die folgenden Fehler: ORA-01847: Tag des Monats zwischen 1 und letzten Tag des Monats muss

ich davon aus bin, es zu tun hat mit der Art, wie die DateTime formatiert ist, aber ich weiß nicht, wie man das auf zuverlässige Weise beheben kann.

+0

Sie würden es nicht am 30. eines Monats mit nur 30 Tagen laufen würden Sie? –

+0

Nein. Es ist fehlgeschlagen mit dem Beispiel, das ich mit DateTime.Now und DateTime.Now.AddDays (1) gezeigt habe; – user12345613

+2

Unterstützt Ihr Treiber definitiv benannte Parameter? Wenn es versucht wird, sie nach Position zu verwenden, wird am Ende der "id" -Wert als "to" -Teil verwendet, der gebrochen werden könnte. Welchen Treiber verwendest du? –

Antwort

10

(Stand Kommentare ...)

Es sieht aus wie in diesem Fall, die Reihenfolge der Parameter matters ... trotz der Tatsache, dass man ihnen Namen gegeben hat. Ich würde das nicht erwartet haben, und es ist das Zeichen einer etwas gebrochen Fahrer, aber Ihr Code ändern zu:

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

sollte es beheben. (Dies ist nicht notwendigerweise die Art, wie Sie Ihre Parameter übrigens konstruieren sollten, aber das ist hier etwas unwichtig.)

Do nicht starten Sie die Angabe der Datum/Uhrzeit-Werte als Zeichenfolgen. Es ist eine wirklich schlechte Idee, um mehr String-Konvertierungen einzuführen, als Sie brauchen.

+0

Ja, ich habe nicht einmal über die Reihenfolge dieses Arrays nachgedacht (was dumm war), da sie Parameter genannt werden. Ich bin auch offen für Kommentare oder Vorschläge zur korrekten Erstellung der Parameter. – user12345613

+0

Nach meiner Erfahrung gibt es viele Dinge in Orakel. NET-Treibern gebrochen, einschließlich Parameter Reihenfolge oder die Notwendigkeit, SQL-Anweisungen zu ändern, um NULL-Referenz Ausnahmen loszuwerden. –

+0

@ user12345613: Ich kann nicht sagen, dass es ein Bereich ist, mit dem ich viel Erfahrung habe, aber wenn Sie die stark typisierte Befehlsparametersammlung verwenden, werden Sie wahrscheinlich Optionen wie 'AddWithValue' erhalten, die das Leben einfacher machen. –

3

umrechnen DateTime Wert auf eine formatierte Datum string:

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; 
} 

Auch wenn Sie einen String-Wert senden, wird die DbType noch auf DateTime, so sollte der Wert richtig erhalten umgewandelt.

+0

Beachten Sie, dass, selbst wenn dies das Problem wäre, Sie wahrscheinlich die invariante Kultur verwenden möchten, und Sie möchten auf jeden Fall ändern "hh" zu " HH ". Ich rate Ihnen dringend davon ab, solche Umstellungen selbst durchzuführen. –

+0

Nichts kommt von @JonSkeet. Einverstanden, ich bin direkt auf das Formatierungsproblem gesprungen und habe nie die Parameterreihenfolge betrachtet. Aktualisiert nach Ihren Vorschlägen. – mgnoonan

2

Oracle erwartet Datumsangaben, die als 'DD-Mon-YYYY' formatiert sind. Daher müssen Sie den Datumswert grundsätzlich auf diese Weise formatieren und dem Parameterwert zuweisen.

Edit: Ich habe festgestellt, dass neuere Versionen von ODP Datum Parameter besser zu behandeln scheinen. Zum Beispiel funktioniert die ganz gut, wenn eine Einschränkung für eine WHERE-Klausel über ein Datum/Zeit-Spalte gibt es:

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

eine Abfrage auf diese Weise mit der neuesten Version von ODP Laufe funktioniert gut. Aber ich habe viel Code, wo Datum/Zeit-Werte als formatierte Zeichenfolgen übergeben werden müssen, damit Oracle sie akzeptiert.

1

Für diejenigen, die es versäumen könnten, finden Sie in den Kommentar von @kprobst unter der akzeptierten Antwort von @JonSkeet:

Es spielt keine Rolle, wie gut Sie die Parameterwerte formatieren usw., wenn Sie zu verwenden sind versuchen Namensbindung, ohne die Eigenschaft BindByName auf Command zu setzen.

(Die gesamte Oracle-Provider-API ist ein Haufen Müll IMHO).

Verwandte Themen